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:
|
preserveBreakIdx:
|
||||||
p.breakIdx = startBlock(p, "while (1) {$n")
|
p.breakIdx = startBlock(p, "while (1) {$n")
|
||||||
|
p.blocks[p.breakIdx].isLoop = true
|
||||||
initLocExpr(p, t.sons[0], a)
|
initLocExpr(p, t.sons[0], a)
|
||||||
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
|
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
|
||||||
let label = assignLabel(p.blocks[p.breakIdx])
|
let label = assignLabel(p.blocks[p.breakIdx])
|
||||||
|
|
@ -265,6 +266,11 @@ proc genBreakStmt(p: BProc, t: PNode) =
|
||||||
var sym = t.sons[0].sym
|
var sym = t.sons[0].sym
|
||||||
assert(sym.loc.k == locOther)
|
assert(sym.loc.k == locOther)
|
||||||
idx = sym.loc.a
|
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])
|
let label = assignLabel(p.blocks[idx])
|
||||||
blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts)
|
blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts)
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ type
|
||||||
# nil if label is not used
|
# nil if label is not used
|
||||||
nestedTryStmts*: int # how many try statements is it nested into
|
nestedTryStmts*: int # how many try statements is it nested into
|
||||||
sections*: TCProcSections # the code beloging
|
sections*: TCProcSections # the code beloging
|
||||||
|
isLoop*: bool # whether block is a loop
|
||||||
|
|
||||||
TCProc{.final.} = object # represents C proc that is currently generated
|
TCProc{.final.} = object # represents C proc that is currently generated
|
||||||
prc*: PSym # the Nimrod proc that this C proc belongs to
|
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
|
id*: int # the ID of the label; positive means that it
|
||||||
# has been used (i.e. the label should be emitted)
|
# has been used (i.e. the label should be emitted)
|
||||||
nestedTryStmts*: int # how many try statements is it nested into
|
nestedTryStmts*: int # how many try statements is it nested into
|
||||||
|
isLoop: bool # whether it's a 'block' or 'while'
|
||||||
|
|
||||||
TGlobals{.final.} = object
|
TGlobals{.final.} = object
|
||||||
typeInfo*, code*: PRope
|
typeInfo*, code*: PRope
|
||||||
|
|
@ -467,6 +468,7 @@ proc genWhileStmt(p: var TProc, n: PNode, r: var TCompRes) =
|
||||||
setlen(p.blocks, length + 1)
|
setlen(p.blocks, length + 1)
|
||||||
p.blocks[length].id = - p.unique
|
p.blocks[length].id = - p.unique
|
||||||
p.blocks[length].nestedTryStmts = p.nestedTryStmts
|
p.blocks[length].nestedTryStmts = p.nestedTryStmts
|
||||||
|
p.blocks[length].isLoop = true
|
||||||
labl = p.unique
|
labl = p.unique
|
||||||
gen(p, n.sons[0], cond)
|
gen(p, n.sons[0], cond)
|
||||||
genStmt(p, n.sons[1], stmt)
|
genStmt(p, n.sons[1], stmt)
|
||||||
|
|
@ -635,13 +637,18 @@ proc genBreakStmt(p: var TProc, n: PNode, r: var TCompRes) =
|
||||||
idx: int
|
idx: int
|
||||||
sym: PSym
|
sym: PSym
|
||||||
genLineDir(p, n, r)
|
genLineDir(p, n, r)
|
||||||
idx = len(p.blocks) - 1
|
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
# named break?
|
# named break?
|
||||||
assert(n.sons[0].kind == nkSym)
|
assert(n.sons[0].kind == nkSym)
|
||||||
sym = n.sons[0].sym
|
sym = n.sons[0].sym
|
||||||
assert(sym.loc.k == locOther)
|
assert(sym.loc.k == locOther)
|
||||||
idx = sym.loc.a
|
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
|
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
|
||||||
finishTryStmt(p, r, p.nestedTryStmts - p.blocks[idx].nestedTryStmts)
|
finishTryStmt(p, r, p.nestedTryStmts - p.blocks[idx].nestedTryStmts)
|
||||||
appf(r.com, "break L$1;$n", [toRope(p.blocks[idx].id)])
|
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)
|
stackTrace(c, n, errTooManyIterations)
|
||||||
break
|
break
|
||||||
|
|
||||||
proc evalBlock(c: PEvalContext, n: PNode): PNode =
|
proc evalBlock(c: PEvalContext, n: PNode): PNode =
|
||||||
result = evalAux(c, n.sons[1], {})
|
result = evalAux(c, n.sons[1], {})
|
||||||
if result.kind == nkBreakStmt:
|
if result.kind == nkBreakStmt:
|
||||||
if result.sons[0] != nil:
|
if result.sons[0] != nil:
|
||||||
assert(result.sons[0].kind == nkSym)
|
assert(result.sons[0].kind == nkSym)
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
assert(n.sons[0].kind == nkSym)
|
assert(n.sons[0].kind == nkSym)
|
||||||
if result.sons[0].sym.id == n.sons[0].sym.id: result = emptyNode
|
if result.sons[0].sym.id == n.sons[0].sym.id: result = emptyNode
|
||||||
else:
|
# blocks can only be left with an explicit label now!
|
||||||
result = emptyNode # consume ``break`` token
|
#else:
|
||||||
|
# result = emptyNode # consume ``break`` token
|
||||||
|
|
||||||
proc evalFinally(c: PEvalContext, n, exc: PNode): PNode =
|
proc evalFinally(c: PEvalContext, n, exc: PNode): PNode =
|
||||||
var finallyNode = lastSon(n)
|
var finallyNode = lastSon(n)
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,8 @@ type
|
||||||
transCon: PTransCon # top of a TransCon stack
|
transCon: PTransCon # top of a TransCon stack
|
||||||
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
|
||||||
blocksyms: seq[PSym]
|
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||||
|
inLoop: int # > 0 if we are in a loop
|
||||||
transformedInnerProcs: TIntSet
|
transformedInnerProcs: TIntSet
|
||||||
PTransf = ref TTransfContext
|
PTransf = ref TTransfContext
|
||||||
|
|
||||||
|
|
@ -252,6 +253,31 @@ proc hasContinue(n: PNode): bool =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if hasContinue(n.sons[i]): return true
|
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 =
|
proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||||
# XXX BUG: What if it contains "continue" and "break"? "break" needs
|
# XXX BUG: 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!
|
||||||
|
|
@ -260,15 +286,13 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||||
# and changing all breaks that belong to a 'block' by annotating it with
|
# and changing all breaks that belong to a 'block' by annotating it with
|
||||||
# a label (if it hasn't one already).
|
# a label (if it hasn't one already).
|
||||||
if hasContinue(n):
|
if hasContinue(n):
|
||||||
var labl = newSym(skLabel, nil, getCurrOwner(c))
|
let labl = newLabel(c, n)
|
||||||
labl.name = getIdent(genPrefix & $labl.id)
|
c.contSyms.add(labl)
|
||||||
labl.info = n.info
|
|
||||||
c.blockSyms.add(labl)
|
|
||||||
|
|
||||||
result = newTransNode(nkBlockStmt, n.info, 2)
|
result = newTransNode(nkBlockStmt, n.info, 2)
|
||||||
result[0] = newSymNode(labl).PTransNode
|
result[0] = newSymNode(labl).PTransNode
|
||||||
result[1] = transform(c, n)
|
result[1] = transform(c, n)
|
||||||
discard c.blockSyms.pop()
|
discard c.contSyms.pop()
|
||||||
else:
|
else:
|
||||||
result = transform(c, n)
|
result = transform(c, n)
|
||||||
|
|
||||||
|
|
@ -631,16 +655,22 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
n.sons[bodyPos] = PNode(transform(c, s.getBody))
|
n.sons[bodyPos] = PNode(transform(c, s.getBody))
|
||||||
if n.kind == nkMethodDef: methodDef(s, false)
|
if n.kind == nkMethodDef: methodDef(s, false)
|
||||||
result = PTransNode(n)
|
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 nkCaseStmt: result = transformCase(c, n)
|
||||||
of nkContinueStmt:
|
of nkContinueStmt:
|
||||||
result = PTransNode(newNode(nkBreakStmt))
|
result = PTransNode(newNode(nkBreakStmt))
|
||||||
var labl = c.blockSyms[c.blockSyms.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 nkWhileStmt:
|
of nkWhileStmt:
|
||||||
|
inc c.inLoop
|
||||||
result = newTransNode(n)
|
result = newTransNode(n)
|
||||||
result[0] = transform(c, n.sons[0])
|
result[0] = transform(c, n.sons[0])
|
||||||
result[1] = transformLoopBody(c, n.sons[1])
|
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)
|
||||||
|
|
@ -671,6 +701,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
result = transformYield(c, n)
|
result = transformYield(c, n)
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
|
of nkBlockStmt, nkBlockExpr:
|
||||||
|
result = transformBlock(c, n)
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
var cnst = getConstExpr(c.module, PNode(result))
|
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 =
|
proc openTransf(module: PSym, filename: string): PPassContext =
|
||||||
var n: PTransf
|
var n: PTransf
|
||||||
new(n)
|
new(n)
|
||||||
n.blocksyms = @[]
|
n.contSyms = @[]
|
||||||
|
n.breakSyms = @[]
|
||||||
n.module = module
|
n.module = module
|
||||||
n.transformedInnerProcs = initIntSet()
|
n.transformedInnerProcs = initIntSet()
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ Nimrod's Garbage Collector
|
||||||
:Author: Andreas Rumpf
|
:Author: Andreas Rumpf
|
||||||
:Version: |nimrodversion|
|
:Version: |nimrodversion|
|
||||||
|
|
||||||
|
"The road to hell is paved with good intentions."
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
|
|
|
||||||
|
|
@ -947,7 +947,9 @@ proc formatBiggestFloat*(f: BiggestFloat, format: TFloatFormat = ffDefault,
|
||||||
## If ``format == ffScientific`` then precision is the maximum number
|
## If ``format == ffScientific`` then precision is the maximum number
|
||||||
## of significant digits to be printed.
|
## of significant digits to be printed.
|
||||||
## `precision`'s default value is the maximum number of meaningful digits
|
## `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']
|
const floatFormatToChar: array[TFloatFormat, char] = ['g', 'f', 'e']
|
||||||
var
|
var
|
||||||
frmtstr {.noinit.}: array[0..5, char]
|
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
|
version 0.9.0
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- fix transformLoopBody
|
- make stack traces part of the exception in debug builds
|
||||||
- make templates hygienic by default
|
- make templates hygienic by default
|
||||||
- ``bind`` for overloaded symbols does not work apparently
|
- ``bind`` for overloaded symbols does not work apparently
|
||||||
- ``=`` should be overloadable; requires specialization for ``=``
|
- ``=`` should be overloadable; requires specialization for ``=``
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue