Proper C scopes for if, try and case statements
even thought the setjmp implementation for try statement won't be used in C++, using properly scoped variables for them is beneficial, because we'll be able to establish a 1:1 relation between nimrod scopes and C scopes. Once we have that, we'll be able to keep the original names of local variables to greatly improve the debugging experience (i.e. watch expressions and hover tooltips will work).
This commit is contained in:
parent
d2b45dbe85
commit
caf7878009
3 changed files with 103 additions and 83 deletions
|
|
@ -47,6 +47,51 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
|
||||||
else:
|
else:
|
||||||
expr(p, ri, a)
|
expr(p, ri, a)
|
||||||
|
|
||||||
|
proc startBlock(p: BProc, start: TFormatStr = "{$n",
|
||||||
|
args: openarray[PRope]): int {.discardable.} =
|
||||||
|
inc(p.labels)
|
||||||
|
result = len(p.blocks)
|
||||||
|
setlen(p.blocks, result + 1)
|
||||||
|
p.blocks[result].id = p.labels
|
||||||
|
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len
|
||||||
|
appcg(p, cpsLocals, start, args)
|
||||||
|
|
||||||
|
proc assignLabel(b: var TBlock): PRope {.inline.} =
|
||||||
|
b.label = con("LA", b.id.toRope)
|
||||||
|
result = b.label
|
||||||
|
|
||||||
|
proc blockBody(b: var TBlock): PRope {.inline.} =
|
||||||
|
return b.sections[cpsLocals].con(b.sections[cpsInit]).con(b.sections[cpsStmts])
|
||||||
|
|
||||||
|
proc endBlock(p: BProc, blockEnd: PRope) =
|
||||||
|
let topBlock = p.blocks.len - 1
|
||||||
|
# the block is merged into the parent block
|
||||||
|
app(p.blocks[topBlock - 1].sections[cpsStmts], p.blocks[topBlock].blockBody)
|
||||||
|
setlen(p.blocks, topBlock)
|
||||||
|
# this is done after the block is popped so $n is
|
||||||
|
# properly indented when pretty printing is enabled
|
||||||
|
app(p.s(cpsStmts), blockEnd)
|
||||||
|
|
||||||
|
var gBlockEndBracket = ropef("}$n")
|
||||||
|
|
||||||
|
proc endBlock(p: BProc) =
|
||||||
|
let topBlock = p.blocks.len - 1
|
||||||
|
let blockEnd = if p.blocks[topBlock].label != nil:
|
||||||
|
ropef("} $1: ;$n", [p.blocks[topBlock].label])
|
||||||
|
else:
|
||||||
|
gBlockEndBracket
|
||||||
|
endBlock(p, blockEnd)
|
||||||
|
|
||||||
|
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
|
||||||
|
startBlock(p)
|
||||||
|
genStmts(p, stmts)
|
||||||
|
endBlock(p)
|
||||||
|
|
||||||
|
template preserveBreakIdx(body: stmt): stmt =
|
||||||
|
var oldBreakIdx = p.breakIdx
|
||||||
|
body
|
||||||
|
p.breakIdx = oldBreakIdx
|
||||||
|
|
||||||
proc genSingleVar(p: BProc, a: PNode) =
|
proc genSingleVar(p: BProc, a: PNode) =
|
||||||
var v = a.sons[0].sym
|
var v = a.sons[0].sym
|
||||||
if sfCompileTime in v.flags: return
|
if sfCompileTime in v.flags: return
|
||||||
|
|
@ -110,17 +155,15 @@ proc genConstStmt(p: BProc, t: PNode) =
|
||||||
proc genIfStmt(p: BProc, n: PNode) =
|
proc genIfStmt(p: BProc, n: PNode) =
|
||||||
#
|
#
|
||||||
# if (!expr1) goto L1;
|
# if (!expr1) goto L1;
|
||||||
# thenPart
|
# { thenPart }
|
||||||
# goto LEnd
|
# goto LEnd
|
||||||
# L1:
|
# L1:
|
||||||
# if (!expr2) goto L2;
|
# if (!expr2) goto L2;
|
||||||
# thenPart2
|
# { thenPart2 }
|
||||||
# goto LEnd
|
# goto LEnd
|
||||||
# L2:
|
# L2:
|
||||||
# elsePart
|
# { elsePart }
|
||||||
# Lend:
|
# Lend:
|
||||||
#
|
|
||||||
## XXX: push blocks here
|
|
||||||
var
|
var
|
||||||
a: TLoc
|
a: TLoc
|
||||||
Lelse: TLabel
|
Lelse: TLabel
|
||||||
|
|
@ -136,12 +179,12 @@ proc genIfStmt(p: BProc, n: PNode) =
|
||||||
appff(p.s(cpsStmts), "if (!$1) goto $2;$n",
|
appff(p.s(cpsStmts), "if (!$1) goto $2;$n",
|
||||||
"br i1 $1, label %LOC$3, label %$2$n" & "LOC$3: $n",
|
"br i1 $1, label %LOC$3, label %$2$n" & "LOC$3: $n",
|
||||||
[rdLoc(a), Lelse, toRope(p.labels)])
|
[rdLoc(a), Lelse, toRope(p.labels)])
|
||||||
genStmts(p, it.sons[1])
|
genSimpleBlock(p, it.sons[1])
|
||||||
if sonsLen(n) > 1:
|
if sonsLen(n) > 1:
|
||||||
appff(p.s(cpsStmts), "goto $1;$n", "br label %$1$n", [Lend])
|
appff(p.s(cpsStmts), "goto $1;$n", "br label %$1$n", [Lend])
|
||||||
fixLabel(p, Lelse)
|
fixLabel(p, Lelse)
|
||||||
of nkElse:
|
of nkElse:
|
||||||
genStmts(p, it.sons[0])
|
genSimpleBlock(p, it.sons[0])
|
||||||
else: internalError(n.info, "genIfStmt()")
|
else: internalError(n.info, "genIfStmt()")
|
||||||
if sonsLen(n) > 1: fixLabel(p, Lend)
|
if sonsLen(n) > 1: fixLabel(p, Lend)
|
||||||
|
|
||||||
|
|
@ -172,36 +215,6 @@ proc genReturnStmt(p: BProc, t: PNode) =
|
||||||
blockLeaveActions(p, min(1, p.nestedTryStmts.len))
|
blockLeaveActions(p, min(1, p.nestedTryStmts.len))
|
||||||
appff(p.s(cpsStmts), "goto BeforeRet;$n", "br label %BeforeRet$n", [])
|
appff(p.s(cpsStmts), "goto BeforeRet;$n", "br label %BeforeRet$n", [])
|
||||||
|
|
||||||
proc startBlock(p: BProc, start = "{$n"): int =
|
|
||||||
inc(p.labels)
|
|
||||||
result = len(p.blocks)
|
|
||||||
setlen(p.blocks, result + 1)
|
|
||||||
p.blocks[result].id = p.labels
|
|
||||||
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len
|
|
||||||
appf(p.s(cpsStmts), start)
|
|
||||||
|
|
||||||
proc assignLabel(b: var TBlock): PRope {.inline.} =
|
|
||||||
b.label = con("LA", b.id.toRope)
|
|
||||||
result = b.label
|
|
||||||
|
|
||||||
proc blockBody(b: var TBlock): PRope {.inline.} =
|
|
||||||
result = b.sections[cpsLocals].con(b.sections[cpsInit]).con(b.sections[cpsStmts])
|
|
||||||
|
|
||||||
var gBlockEndBracket = ropef("}$n")
|
|
||||||
|
|
||||||
proc endBlock(p: BProc) =
|
|
||||||
let topBlock = p.blocks.len - 1
|
|
||||||
let blockEnd = if p.blocks[topBlock].label != nil:
|
|
||||||
ropef("} $1: ;$n", [p.blocks[topBlock].label])
|
|
||||||
else:
|
|
||||||
gBlockEndBracket
|
|
||||||
# the block is merged into the parent block
|
|
||||||
app(p.blocks[topBlock - 1].sections[cpsStmts], p.blocks[topBlock].blockBody)
|
|
||||||
setlen(p.blocks, topBlock)
|
|
||||||
# this is done after the block is popped so $n is
|
|
||||||
# properly indented when pretty printing is enabled
|
|
||||||
app(p.s(cpsStmts), blockEnd)
|
|
||||||
|
|
||||||
proc genWhileStmt(p: BProc, t: PNode) =
|
proc genWhileStmt(p: BProc, t: PNode) =
|
||||||
# we don't generate labels here as for example GCC would produce
|
# we don't generate labels here as for example GCC would produce
|
||||||
# significantly worse code
|
# significantly worse code
|
||||||
|
|
@ -212,10 +225,11 @@ proc genWhileStmt(p: BProc, t: PNode) =
|
||||||
inc(p.withinLoop)
|
inc(p.withinLoop)
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
|
|
||||||
var blockIdx = startBlock(p, "while (1) {$n")
|
preserveBreakIdx:
|
||||||
|
p.breakIdx = startBlock(p, "while (1) {$n")
|
||||||
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[blockIdx])
|
let label = assignLabel(p.blocks[p.breakIdx])
|
||||||
appf(p.s(cpsStmts), "if (!$1) goto $2;$n", [rdLoc(a), label])
|
appf(p.s(cpsStmts), "if (!$1) goto $2;$n", [rdLoc(a), label])
|
||||||
genStmts(p, t.sons[1])
|
genStmts(p, t.sons[1])
|
||||||
endBlock(p)
|
endBlock(p)
|
||||||
|
|
@ -223,19 +237,20 @@ proc genWhileStmt(p: BProc, t: PNode) =
|
||||||
dec(p.withinLoop)
|
dec(p.withinLoop)
|
||||||
|
|
||||||
proc genBlock(p: BProc, t: PNode, d: var TLoc) =
|
proc genBlock(p: BProc, t: PNode, d: var TLoc) =
|
||||||
var idx = startBlock(p)
|
preserveBreakIdx:
|
||||||
|
p.breakIdx = startBlock(p)
|
||||||
if t.sons[0].kind != nkEmpty:
|
if t.sons[0].kind != nkEmpty:
|
||||||
# named block?
|
# named block?
|
||||||
assert(t.sons[0].kind == nkSym)
|
assert(t.sons[0].kind == nkSym)
|
||||||
var sym = t.sons[0].sym
|
var sym = t.sons[0].sym
|
||||||
sym.loc.k = locOther
|
sym.loc.k = locOther
|
||||||
sym.loc.a = idx
|
sym.loc.a = p.breakIdx
|
||||||
if t.kind == nkBlockExpr: genStmtListExpr(p, t.sons[1], d)
|
if t.kind == nkBlockExpr: genStmtListExpr(p, t.sons[1], d)
|
||||||
else: genStmts(p, t.sons[1])
|
else: genStmts(p, t.sons[1])
|
||||||
endBlock(p)
|
endBlock(p)
|
||||||
|
|
||||||
proc genBreakStmt(p: BProc, t: PNode) =
|
proc genBreakStmt(p: BProc, t: PNode) =
|
||||||
var idx = len(p.blocks) - 1
|
var idx = p.breakIdx
|
||||||
if t.sons[0].kind != nkEmpty:
|
if t.sons[0].kind != nkEmpty:
|
||||||
# named break?
|
# named break?
|
||||||
assert(t.sons[0].kind == nkSym)
|
assert(t.sons[0].kind == nkSym)
|
||||||
|
|
@ -290,10 +305,10 @@ proc genCaseSecondPass(p: BProc, t: PNode, labId, until: int): TLabel =
|
||||||
appf(p.s(cpsStmts), "LA$1: ;$n", [toRope(labId + i)])
|
appf(p.s(cpsStmts), "LA$1: ;$n", [toRope(labId + i)])
|
||||||
if t.sons[i].kind == nkOfBranch:
|
if t.sons[i].kind == nkOfBranch:
|
||||||
var length = sonsLen(t.sons[i])
|
var length = sonsLen(t.sons[i])
|
||||||
genStmts(p, t.sons[i].sons[length - 1])
|
genSimpleBlock(p, t.sons[i].sons[length - 1])
|
||||||
appf(p.s(cpsStmts), "goto $1;$n", [Lend])
|
appf(p.s(cpsStmts), "goto $1;$n", [Lend])
|
||||||
else:
|
else:
|
||||||
genStmts(p, t.sons[i].sons[0])
|
genSimpleBlock(p, t.sons[i].sons[0])
|
||||||
result = Lend
|
result = Lend
|
||||||
|
|
||||||
proc genIfForCaseUntil(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr,
|
proc genIfForCaseUntil(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr,
|
||||||
|
|
@ -428,11 +443,11 @@ proc genOrdinalCase(p: BProc, n: PNode) =
|
||||||
var branch = n[i]
|
var branch = n[i]
|
||||||
if branch.kind == nkOfBranch:
|
if branch.kind == nkOfBranch:
|
||||||
genCaseRange(p, branch)
|
genCaseRange(p, branch)
|
||||||
genStmts(p, branch.lastSon)
|
genSimpleBlock(p, branch.lastSon)
|
||||||
else:
|
else:
|
||||||
# else part of case statement:
|
# else part of case statement:
|
||||||
appf(p.s(cpsStmts), "default:$n")
|
appf(p.s(cpsStmts), "default:$n")
|
||||||
genStmts(p, branch[0])
|
genSimpleBlock(p, branch[0])
|
||||||
hasDefault = true
|
hasDefault = true
|
||||||
appf(p.s(cpsStmts), "break;$n")
|
appf(p.s(cpsStmts), "break;$n")
|
||||||
if (hasAssume in CC[ccompiler].props) and not hasDefault:
|
if (hasAssume in CC[ccompiler].props) and not hasDefault:
|
||||||
|
|
@ -484,6 +499,8 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
|
||||||
# excHandler = excHandler->prev; // we handled the exception
|
# excHandler = excHandler->prev; // we handled the exception
|
||||||
# finallyPart();
|
# finallyPart();
|
||||||
# if (tmpRethrow) throw;
|
# if (tmpRethrow) throw;
|
||||||
|
#
|
||||||
|
# XXX: push blocks
|
||||||
var
|
var
|
||||||
rethrowFlag: PRope
|
rethrowFlag: PRope
|
||||||
exc: PRope
|
exc: PRope
|
||||||
|
|
@ -549,12 +566,13 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||||
# clearException();
|
# clearException();
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
|
# {
|
||||||
# /* finally: */
|
# /* finally: */
|
||||||
# printf('fin!\n');
|
# printf('fin!\n');
|
||||||
|
# }
|
||||||
# if (exception not cleared)
|
# if (exception not cleared)
|
||||||
# propagateCurrentException();
|
# propagateCurrentException();
|
||||||
#
|
#
|
||||||
# XXX: push blocks here
|
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
var safePoint = getTempName()
|
var safePoint = getTempName()
|
||||||
discard cgsym(p.module, "E_Base")
|
discard cgsym(p.module, "E_Base")
|
||||||
|
|
@ -563,24 +581,25 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||||
"$1.status = setjmp($1.context);$n", [safePoint])
|
"$1.status = setjmp($1.context);$n", [safePoint])
|
||||||
if optStackTrace in p.Options:
|
if optStackTrace in p.Options:
|
||||||
appcg(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
|
appcg(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
|
||||||
appf(p.s(cpsStmts), "if ($1.status == 0) {$n", [safePoint])
|
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
|
||||||
var length = sonsLen(t)
|
var length = sonsLen(t)
|
||||||
add(p.nestedTryStmts, t)
|
add(p.nestedTryStmts, t)
|
||||||
genStmts(p, t.sons[0])
|
genStmts(p, t.sons[0])
|
||||||
appcg(p, cpsStmts, "#popSafePoint();$n} else {$n#popSafePoint();$n")
|
endBlock(p, ropecg(p.module, "#popSafePoint();$n } else {$n#popSafePoint();$n"))
|
||||||
discard pop(p.nestedTryStmts)
|
discard pop(p.nestedTryStmts)
|
||||||
var i = 1
|
var i = 1
|
||||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
||||||
var blen = sonsLen(t.sons[i])
|
var blen = sonsLen(t.sons[i])
|
||||||
if blen == 1:
|
if blen == 1:
|
||||||
# general except section:
|
# general except section:
|
||||||
if i > 1: appf(p.s(cpsStmts), "else {$n")
|
if i > 1: appf(p.s(cpsStmts), "else")
|
||||||
|
startBlock(p)
|
||||||
appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
|
appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
|
||||||
inc p.popCurrExc
|
inc p.popCurrExc
|
||||||
genStmts(p, t.sons[i].sons[0])
|
genStmts(p, t.sons[i].sons[0])
|
||||||
dec p.popCurrExc
|
dec p.popCurrExc
|
||||||
appcg(p, cpsStmts, "#popCurrentException();$n", [])
|
appcg(p, cpsStmts, "#popCurrentException();$n", [])
|
||||||
if i > 1: appf(p.s(cpsStmts), "}$n")
|
endBlock(p)
|
||||||
else:
|
else:
|
||||||
inc p.popCurrExc
|
inc p.popCurrExc
|
||||||
var orExpr: PRope = nil
|
var orExpr: PRope = nil
|
||||||
|
|
@ -591,16 +610,15 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||||
"#isObj(#getCurrentException()->Sup.m_type, $1)",
|
"#isObj(#getCurrentException()->Sup.m_type, $1)",
|
||||||
[genTypeInfo(p.module, t.sons[i].sons[j].typ)])
|
[genTypeInfo(p.module, t.sons[i].sons[j].typ)])
|
||||||
if i > 1: app(p.s(cpsStmts), "else ")
|
if i > 1: app(p.s(cpsStmts), "else ")
|
||||||
appf(p.s(cpsStmts), "if ($1) {$n", [orExpr])
|
startBlock(p, "if ($1) {$n", [orExpr])
|
||||||
appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
|
appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
|
||||||
genStmts(p, t.sons[i].sons[blen-1])
|
genStmts(p, t.sons[i].sons[blen-1])
|
||||||
dec p.popCurrExc
|
dec p.popCurrExc
|
||||||
# code to clear the exception:
|
endBlock(p, ropecg(p.module, "#popCurrentException();}$n"))
|
||||||
appcg(p, cpsStmts, "#popCurrentException();}$n", [])
|
|
||||||
inc(i)
|
inc(i)
|
||||||
appf(p.s(cpsStmts), "}$n") # end of if statement
|
appf(p.s(cpsStmts), "}$n") # end of else block
|
||||||
if i < length and t.sons[i].kind == nkFinally:
|
if i < length and t.sons[i].kind == nkFinally:
|
||||||
genStmts(p, t.sons[i].sons[0])
|
genSimpleBlock(p, t.sons[i].sons[0])
|
||||||
appcg(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint])
|
appcg(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint])
|
||||||
|
|
||||||
proc genAsmOrEmitStmt(p: BProc, t: PNode): PRope =
|
proc genAsmOrEmitStmt(p: BProc, t: PNode): PRope =
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,8 @@ type
|
||||||
# before 'break'|'return'
|
# before 'break'|'return'
|
||||||
labels*: Natural # for generating unique labels in the C proc
|
labels*: Natural # for generating unique labels in the C proc
|
||||||
blocks*: seq[TBlock] # nested blocks
|
blocks*: seq[TBlock] # nested blocks
|
||||||
|
breakIdx*: int # the block that will be exited
|
||||||
|
# with a regular break
|
||||||
options*: TOptions # options that should be used for code
|
options*: TOptions # options that should be used for code
|
||||||
# generation; this is the same as prc.options
|
# generation; this is the same as prc.options
|
||||||
# unless prc == nil
|
# unless prc == nil
|
||||||
|
|
|
||||||
|
|
@ -1593,7 +1593,7 @@ proc echo*[Ty](x: openarray[Ty]) {.magic: "Echo", noSideEffect.}
|
||||||
template newException*(exceptn: typeDesc, message: string): expr =
|
template newException*(exceptn: typeDesc, message: string): expr =
|
||||||
## creates an exception object of type ``exceptn`` and sets its ``msg`` field
|
## creates an exception object of type ``exceptn`` and sets its ``msg`` field
|
||||||
## to `message`. Returns the new exception object.
|
## to `message`. Returns the new exception object.
|
||||||
block: # open a new scope
|
# block: # open a new scope
|
||||||
var
|
var
|
||||||
e: ref exceptn
|
e: ref exceptn
|
||||||
new(e)
|
new(e)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue