fixes #109
This commit is contained in:
parent
e6019b6f98
commit
15dd3a2251
9 changed files with 95 additions and 16 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)])
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ Nimrod's Garbage Collector
|
|||
:Author: Andreas Rumpf
|
||||
:Version: |nimrodversion|
|
||||
|
||||
"The road to hell is paved with good intentions."
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
|
|
|||
|
|
@ -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
28
tests/run/tcontinue.nim
Normal 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"
|
||||
2
todo.txt
2
todo.txt
|
|
@ -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 ``=``
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue