This commit is contained in:
Araq 2012-05-20 10:56:17 +02:00
commit 15dd3a2251
9 changed files with 95 additions and 16 deletions

View file

@ -235,6 +235,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
preserveBreakIdx:
p.breakIdx = startBlock(p, "while (1) {$n")
p.blocks[p.breakIdx].isLoop = true
initLocExpr(p, t.sons[0], a)
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
let label = assignLabel(p.blocks[p.breakIdx])
@ -265,6 +266,11 @@ proc genBreakStmt(p: BProc, t: PNode) =
var sym = t.sons[0].sym
assert(sym.loc.k == locOther)
idx = sym.loc.a
else:
# an unnamed 'break' can only break a loop after 'transf' pass:
while idx >= 0 and not p.blocks[idx].isLoop: dec idx
if idx < 0 or not p.blocks[idx].isLoop:
InternalError(t.info, "no loop to break")
let label = assignLabel(p.blocks[idx])
blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts)
genLineDir(p, t)

View file

@ -54,6 +54,7 @@ type
# nil if label is not used
nestedTryStmts*: int # how many try statements is it nested into
sections*: TCProcSections # the code beloging
isLoop*: bool # whether block is a loop
TCProc{.final.} = object # represents C proc that is currently generated
prc*: PSym # the Nimrod proc that this C proc belongs to

View file

@ -47,6 +47,7 @@ type
id*: int # the ID of the label; positive means that it
# has been used (i.e. the label should be emitted)
nestedTryStmts*: int # how many try statements is it nested into
isLoop: bool # whether it's a 'block' or 'while'
TGlobals{.final.} = object
typeInfo*, code*: PRope
@ -467,6 +468,7 @@ proc genWhileStmt(p: var TProc, n: PNode, r: var TCompRes) =
setlen(p.blocks, length + 1)
p.blocks[length].id = - p.unique
p.blocks[length].nestedTryStmts = p.nestedTryStmts
p.blocks[length].isLoop = true
labl = p.unique
gen(p, n.sons[0], cond)
genStmt(p, n.sons[1], stmt)
@ -635,13 +637,18 @@ proc genBreakStmt(p: var TProc, n: PNode, r: var TCompRes) =
idx: int
sym: PSym
genLineDir(p, n, r)
idx = len(p.blocks) - 1
if n.sons[0].kind != nkEmpty:
# named break?
assert(n.sons[0].kind == nkSym)
sym = n.sons[0].sym
assert(sym.loc.k == locOther)
idx = sym.loc.a
else:
# an unnamed 'break' can only break a loop after 'transf' pass:
idx = len(p.blocks) - 1
while idx >= 0 and not p.blocks[idx].isLoop: dec idx
if idx < 0 or not p.blocks[idx].isLoop:
InternalError(n.info, "no loop to break")
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
finishTryStmt(p, r, p.nestedTryStmts - p.blocks[idx].nestedTryStmts)
appf(r.com, "break L$1;$n", [toRope(p.blocks[idx].id)])

View file

@ -162,16 +162,17 @@ proc evalWhile(c: PEvalContext, n: PNode): PNode =
stackTrace(c, n, errTooManyIterations)
break
proc evalBlock(c: PEvalContext, n: PNode): PNode =
proc evalBlock(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[1], {})
if result.kind == nkBreakStmt:
if result.kind == nkBreakStmt:
if result.sons[0] != nil:
assert(result.sons[0].kind == nkSym)
if n.sons[0].kind != nkEmpty:
assert(n.sons[0].kind == nkSym)
if result.sons[0].sym.id == n.sons[0].sym.id: result = emptyNode
else:
result = emptyNode # consume ``break`` token
# blocks can only be left with an explicit label now!
#else:
# result = emptyNode # consume ``break`` token
proc evalFinally(c: PEvalContext, n, exc: PNode): PNode =
var finallyNode = lastSon(n)

View file

@ -46,7 +46,8 @@ type
transCon: PTransCon # top of a TransCon stack
inlining: int # > 0 if we are in inlining context (copy vars)
nestedProcs: int # > 0 if we are in a nested proc
blocksyms: seq[PSym]
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
inLoop: int # > 0 if we are in a loop
transformedInnerProcs: TIntSet
PTransf = ref TTransfContext
@ -252,6 +253,31 @@ proc hasContinue(n: PNode): bool =
for i in countup(0, sonsLen(n) - 1):
if hasContinue(n.sons[i]): return true
proc newLabel(c: PTransf, n: PNode): PSym =
result = newSym(skLabel, nil, getCurrOwner(c))
result.name = getIdent(genPrefix & $result.id)
result.info = n.info
proc transformBlock(c: PTransf, n: PNode): PTransNode =
var labl: PSym
if n.sons[0].kind != nkEmpty:
# already named block? -> Push symbol on the stack:
labl = n.sons[0].sym
else:
labl = newLabel(c, n)
c.breakSyms.add(labl)
result = transformSons(c, n)
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 =
# XXX BUG: What if it contains "continue" and "break"? "break" needs
# an explicit label too, but not the same!
@ -260,15 +286,13 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
# and changing all breaks that belong to a 'block' by annotating it with
# a label (if it hasn't one already).
if hasContinue(n):
var labl = newSym(skLabel, nil, getCurrOwner(c))
labl.name = getIdent(genPrefix & $labl.id)
labl.info = n.info
c.blockSyms.add(labl)
let labl = newLabel(c, n)
c.contSyms.add(labl)
result = newTransNode(nkBlockStmt, n.info, 2)
result[0] = newSymNode(labl).PTransNode
result[1] = transform(c, n)
discard c.blockSyms.pop()
discard c.contSyms.pop()
else:
result = transform(c, n)
@ -631,16 +655,22 @@ proc transform(c: PTransf, n: PNode): PTransNode =
n.sons[bodyPos] = PNode(transform(c, s.getBody))
if n.kind == nkMethodDef: methodDef(s, false)
result = PTransNode(n)
of nkForStmt: result = transformFor(c, n)
of nkForStmt:
inc c.inLoop
result = transformFor(c, n)
dec c.inLoop
of nkCaseStmt: result = transformCase(c, n)
of nkContinueStmt:
result = PTransNode(newNode(nkBreakStmt))
var labl = c.blockSyms[c.blockSyms.high]
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 nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
nkCallStrLit:
result = transformCall(c, n)
@ -671,6 +701,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
result = transformYield(c, n)
else:
result = transformSons(c, n)
of nkBlockStmt, nkBlockExpr:
result = transformBlock(c, n)
else:
result = transformSons(c, n)
var cnst = getConstExpr(c.module, PNode(result))
@ -692,7 +724,8 @@ proc processTransf(context: PPassContext, n: PNode): PNode =
proc openTransf(module: PSym, filename: string): PPassContext =
var n: PTransf
new(n)
n.blocksyms = @[]
n.contSyms = @[]
n.breakSyms = @[]
n.module = module
n.transformedInnerProcs = initIntSet()
result = n

View file

@ -5,6 +5,7 @@ Nimrod's Garbage Collector
:Author: Andreas Rumpf
:Version: |nimrodversion|
"The road to hell is paved with good intentions."
Introduction
============

View file

@ -947,7 +947,9 @@ proc formatBiggestFloat*(f: BiggestFloat, format: TFloatFormat = ffDefault,
## If ``format == ffScientific`` then precision is the maximum number
## of significant digits to be printed.
## `precision`'s default value is the maximum number of meaningful digits
## after the decimal point for Nimrod's ``biggestFloat`` type.
## after the decimal point for Nimrod's ``biggestFloat`` type.
##
## If ``precision == 0``, it uses the
const floatFormatToChar: array[TFloatFormat, char] = ['g', 'f', 'e']
var
frmtstr {.noinit.}: array[0..5, char]

28
tests/run/tcontinue.nim Normal file
View file

@ -0,0 +1,28 @@
discard """
output: "came here"
"""
var i = 0
while i < 400:
if i == 10: break
elif i == 3:
inc i
continue
inc i
var f = "failure"
var j = 0
while j < 300:
for x in 0..34:
if j < 300: continue
if x == 10:
echo "failure: should never happen"
break
f = "came here"
break
if i == 10:
echo f
else:
echo "failure"

View file

@ -1,7 +1,7 @@
version 0.9.0
=============
- fix transformLoopBody
- make stack traces part of the exception in debug builds
- make templates hygienic by default
- ``bind`` for overloaded symbols does not work apparently
- ``=`` should be overloadable; requires specialization for ``=``