Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
Araq 2012-04-15 10:02:35 +02:00
commit da9ff288d9
20 changed files with 440 additions and 264 deletions

View file

@ -244,12 +244,17 @@ const
sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
sfNoInit* = sfMainModule # don't generate code to init the variable sfNoInit* = sfMainModule # don't generate code to init the variable
sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded sfImmediate* = sfDeadCodeElim
# without considering any possible overloads # macro or template is immediately expanded
# without considering any possible overloads
sfAnon* = sfCompilerProc # symbol name that was generated by the compiler sfAnon* = sfDiscardable
# the compiler will avoid printing such names # symbol name that was generated by the compiler
# in user messages. # the compiler will avoid printing such names
# in user messages.
sfShadowed* = sfInnerProc
# a variable that was shadowed in some inner scope
const const
# getting ready for the future expr/stmt merge # getting ready for the future expr/stmt merge
@ -647,6 +652,14 @@ const
resultPos* = 5 resultPos* = 5
dispatcherPos* = 6 # caution: if method has no 'result' it can be position 5! dispatcherPos* = 6 # caution: if method has no 'result' it can be position 5!
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
nkCommand, nkCallStrLit}
nkLambdaKinds* = {nkLambda, nkDo}
skLocalVars* = {skVar, skLet, skForVar, skParam}
# creator procs: # creator procs:
proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym): PSym proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym): PSym
proc NewType*(kind: TTypeKind, owner: PSym): PType proc NewType*(kind: TTypeKind, owner: PSym): PType
@ -691,11 +704,6 @@ proc copyNode*(src: PNode): PNode
proc copyTree*(src: PNode): PNode proc copyTree*(src: PNode): PNode
# does copy its sons! # does copy its sons!
const nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand,
nkCallStrLit}
const nkLambdaKinds* = {nkLambda, nkDo}
proc isCallExpr*(n: PNode): bool = proc isCallExpr*(n: PNode): bool =
result = n.kind in nkCallKinds result = n.kind in nkCallKinds

View file

@ -6,6 +6,8 @@
# 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.
# #
#
# included from cgen.nim
proc leftAppearsOnRightSide(le, ri: PNode): bool = proc leftAppearsOnRightSide(le, ri: PNode): bool =
if le != nil: if le != nil:
@ -16,9 +18,6 @@ proc leftAppearsOnRightSide(le, ri: PNode): bool =
proc hasNoInit(call: PNode): bool {.inline.} = proc hasNoInit(call: PNode): bool {.inline.} =
result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags
proc resetLoc(p: BProc, d: var TLoc) =
zeroVar(p, d, containsGarbageCollectedRef(d.t))
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) = proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) =
var pl = pl var pl = pl
var typ = ri.sons[0].typ # getUniqueType() is too expensive here! var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
@ -34,15 +33,15 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) =
resetLoc(p, d) resetLoc(p, d)
app(pl, addrLoc(d)) app(pl, addrLoc(d))
app(pl, ")") app(pl, ")")
app(p.s[cpsStmts], pl) app(p.s(cpsStmts), pl)
appf(p.s[cpsStmts], ";$n") appf(p.s(cpsStmts), ";$n")
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ.sons[0], tmp) getTemp(p, typ.sons[0], tmp)
app(pl, addrLoc(tmp)) app(pl, addrLoc(tmp))
app(pl, ")") app(pl, ")")
app(p.s[cpsStmts], pl) app(p.s(cpsStmts), pl)
appf(p.s[cpsStmts], ";$n") appf(p.s(cpsStmts), ";$n")
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
else: else:
app(pl, ")") app(pl, ")")
@ -54,8 +53,8 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) =
genAssignment(p, d, list, {}) # no need for deep copying genAssignment(p, d, list, {}) # no need for deep copying
else: else:
app(pl, ")") app(pl, ")")
app(p.s[cpsStmts], pl) app(p.s(cpsStmts), pl)
appf(p.s[cpsStmts], ";$n") appf(p.s(cpsStmts), ";$n")
proc isInCurrentFrame(p: BProc, n: PNode): bool = proc isInCurrentFrame(p: BProc, n: PNode): bool =
# checks if `n` is an expression that refers to the current frame; # checks if `n` is an expression that refers to the current frame;
@ -164,7 +163,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if i < length - 1: app(pl, ", ") if i < length - 1: app(pl, ", ")
template genCallPattern = template genCallPattern =
appf(p.s[cpsStmts], CallPattern, op.r, pl, pl.addComma, rawProc) appf(p.s(cpsStmts), CallPattern, op.r, pl, pl.addComma, rawProc)
let rawProc = getRawProcType(p, typ) let rawProc = getRawProcType(p, typ)
if typ.sons[0] != nil: if typ.sons[0] != nil:
@ -179,13 +178,13 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
resetLoc(p, d) resetLoc(p, d)
app(pl, addrLoc(d)) app(pl, addrLoc(d))
genCallPattern() genCallPattern()
appf(p.s[cpsStmts], ";$n") appf(p.s(cpsStmts), ";$n")
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ.sons[0], tmp) getTemp(p, typ.sons[0], tmp)
app(pl, addrLoc(tmp)) app(pl, addrLoc(tmp))
genCallPattern() genCallPattern()
appf(p.s[cpsStmts], ";$n") appf(p.s(cpsStmts), ";$n")
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
else: else:
if d.k == locNone: getTemp(p, typ.sons[0], d) if d.k == locNone: getTemp(p, typ.sons[0], d)
@ -196,7 +195,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genAssignment(p, d, list, {}) # no need for deep copying genAssignment(p, d, list, {}) # no need for deep copying
else: else:
genCallPattern() genCallPattern()
appf(p.s[cpsStmts], ";$n") appf(p.s(cpsStmts), ";$n")
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op, a: TLoc var op, a: TLoc
@ -261,15 +260,15 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
app(pl, "Result: ") app(pl, "Result: ")
app(pl, addrLoc(d)) app(pl, addrLoc(d))
app(pl, "]") app(pl, "]")
app(p.s[cpsStmts], pl) app(p.s(cpsStmts), pl)
appf(p.s[cpsStmts], ";$n") appf(p.s(cpsStmts), ";$n")
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ.sons[0], tmp) getTemp(p, typ.sons[0], tmp)
app(pl, addrLoc(tmp)) app(pl, addrLoc(tmp))
app(pl, "]") app(pl, "]")
app(p.s[cpsStmts], pl) app(p.s(cpsStmts), pl)
appf(p.s[cpsStmts], ";$n") appf(p.s(cpsStmts), ";$n")
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
else: else:
app(pl, "]") app(pl, "]")
@ -281,8 +280,8 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
genAssignment(p, d, list, {}) # no need for deep copying genAssignment(p, d, list, {}) # no need for deep copying
else: else:
app(pl, "]") app(pl, "]")
app(p.s[cpsStmts], pl) app(p.s(cpsStmts), pl)
appf(p.s[cpsStmts], ";$n") appf(p.s(cpsStmts), ";$n")
proc genCall(p: BProc, e: PNode, d: var TLoc) = proc genCall(p: BProc, e: PNode, d: var TLoc) =
if e.sons[0].typ.callConv == ccClosure: if e.sons[0].typ.callConv == ccClosure:

View file

@ -160,7 +160,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if dest.s == OnStack or optRefcGC notin gGlobalOptions: if dest.s == OnStack or optRefcGC notin gGlobalOptions:
appf(p.s[cpsStmts], "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) appf(p.s(cpsStmts), "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
if needToKeepAlive in flags: keepAlive(p, dest) if needToKeepAlive in flags: keepAlive(p, dest)
elif dest.s == OnHeap: elif dest.s == OnHeap:
# location is on heap # location is on heap
@ -180,13 +180,13 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# appf(p.s[cpsStmts], 'if ($1) nimGCunref($1);$n', [rdLoc(dest)]) # appf(p.s[cpsStmts], 'if ($1) nimGCunref($1);$n', [rdLoc(dest)])
# appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]) # appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)])
if canFormAcycle(dest.t): if canFormAcycle(dest.t):
appcg(p.module, p.s[cpsStmts], "#asgnRef((void**) $1, $2);$n", appcg(p.module, p.s(cpsStmts), "#asgnRef((void**) $1, $2);$n",
[addrLoc(dest), rdLoc(src)]) [addrLoc(dest), rdLoc(src)])
else: else:
appcg(p.module, p.s[cpsStmts], "#asgnRefNoCycle((void**) $1, $2);$n", appcg(p.module, p.s(cpsStmts), "#asgnRefNoCycle((void**) $1, $2);$n",
[addrLoc(dest), rdLoc(src)]) [addrLoc(dest), rdLoc(src)])
else: else:
appcg(p.module, p.s[cpsStmts], "#unsureAsgnRef((void**) $1, $2);$n", appcg(p.module, p.s(cpsStmts), "#unsureAsgnRef((void**) $1, $2);$n",
[addrLoc(dest), rdLoc(src)]) [addrLoc(dest), rdLoc(src)])
if needToKeepAlive in flags: keepAlive(p, dest) if needToKeepAlive in flags: keepAlive(p, dest)
@ -736,9 +736,9 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
expr(p, e.sons[1], tmp) expr(p, e.sons[1], tmp)
L = getLabel(p) L = getLabel(p)
if m == mOr: if m == mOr:
appf(p.s[cpsStmts], "if ($1) goto $2;$n", [rdLoc(tmp), L]) appf(p.s(cpsStmts), "if ($1) goto $2;$n", [rdLoc(tmp), L])
else: else:
appf(p.s[cpsStmts], "if (!($1)) goto $2;$n", [rdLoc(tmp), L]) appf(p.s(cpsStmts), "if (!($1)) goto $2;$n", [rdLoc(tmp), L])
expr(p, e.sons[2], tmp) expr(p, e.sons[2], tmp)
fixLabel(p, L) fixLabel(p, L)
if d.k == locNone: if d.k == locNone:
@ -771,9 +771,9 @@ proc genIfExpr(p: BProc, n: PNode, d: var TLoc) =
of nkElifExpr: of nkElifExpr:
initLocExpr(p, it.sons[0], a) initLocExpr(p, it.sons[0], a)
Lelse = getLabel(p) Lelse = getLabel(p)
appf(p.s[cpsStmts], "if (!$1) goto $2;$n", [rdLoc(a), Lelse]) appf(p.s(cpsStmts), "if (!$1) goto $2;$n", [rdLoc(a), Lelse])
expr(p, it.sons[1], tmp) expr(p, it.sons[1], tmp)
appf(p.s[cpsStmts], "goto $1;$n", [Lend]) appf(p.s(cpsStmts), "goto $1;$n", [Lend])
fixLabel(p, Lelse) fixLabel(p, Lelse)
of nkElseExpr: of nkElseExpr:
expr(p, it.sons[0], tmp) expr(p, it.sons[0], tmp)
@ -832,7 +832,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()]) appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
appcg(p.module, appends, "#appendString($1, $2);$n", [tmp.r, rdLoc(a)]) appcg(p.module, appends, "#appendString($1, $2);$n", [tmp.r, rdLoc(a)])
appcg(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.r, lens, toRope(L)]) appcg(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.r, lens, toRope(L)])
app(p.s[cpsStmts], appends) app(p.s(cpsStmts), appends)
if d.k == locNone: if d.k == locNone:
d = tmp d = tmp
keepAlive(p, tmp) keepAlive(p, tmp)
@ -874,7 +874,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
appcg(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", appcg(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
[rdLoc(dest), lens, toRope(L)]) [rdLoc(dest), lens, toRope(L)])
keepAlive(p, dest) keepAlive(p, dest)
app(p.s[cpsStmts], appends) app(p.s(cpsStmts), appends)
proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
# seq &= x --> # seq &= x -->
@ -1171,7 +1171,7 @@ proc binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) =
assert(d.k == locNone) assert(d.k == locNone)
InitLocExpr(p, e.sons[1], a) InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b) InitLocExpr(p, e.sons[2], b)
appf(p.s[cpsStmts], frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]) appf(p.s(cpsStmts), frmt, [rdLoc(a), rdSetElemLoc(b, a.t)])
proc genInOp(p: BProc, e: PNode, d: var TLoc) = proc genInOp(p: BProc, e: PNode, d: var TLoc) =
var a, b, x, y: TLoc var a, b, x, y: TLoc
@ -1247,7 +1247,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
if d.k == locNone: getTemp(p, a.t, d) if d.k == locNone: getTemp(p, a.t, d)
appf(p.s[cpsStmts], lookupOpr[op], appf(p.s(cpsStmts), lookupOpr[op],
[rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)]) [rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
of mEqSet: of mEqSet:
binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)") binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)")
@ -1257,7 +1257,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
if d.k == locNone: getTemp(p, a.t, d) if d.k == locNone: getTemp(p, a.t, d)
appf(p.s[cpsStmts], appf(p.s(cpsStmts),
"for ($1 = 0; $1 < $2; $1++) $n" & "for ($1 = 0; $1 < $2; $1++) $n" &
" $3[$1] = $4[$1] $6 $5[$1];$n", [ " $3[$1] = $4[$1] $6 $5[$1];$n", [
rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b), rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b),
@ -1467,35 +1467,35 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
if d.k == locNone: getTemp(p, e.typ, d) if d.k == locNone: getTemp(p, e.typ, d)
if getSize(e.typ) > 8: if getSize(e.typ) > 8:
# big set: # big set:
appf(p.s[cpsStmts], "memset($1, 0, sizeof($1));$n", [rdLoc(d)]) appf(p.s(cpsStmts), "memset($1, 0, sizeof($1));$n", [rdLoc(d)])
for i in countup(0, sonsLen(e) - 1): for i in countup(0, sonsLen(e) - 1):
if e.sons[i].kind == nkRange: if e.sons[i].kind == nkRange:
getTemp(p, getSysType(tyInt), idx) # our counter getTemp(p, getSysType(tyInt), idx) # our counter
initLocExpr(p, e.sons[i].sons[0], a) initLocExpr(p, e.sons[i].sons[0], a)
initLocExpr(p, e.sons[i].sons[1], b) initLocExpr(p, e.sons[i].sons[1], b)
appf(p.s[cpsStmts], "for ($1 = $3; $1 <= $4; $1++) $n" & appf(p.s(cpsStmts), "for ($1 = $3; $1 <= $4; $1++) $n" &
"$2[$1/8] |=(1<<($1%8));$n", [rdLoc(idx), rdLoc(d), "$2[$1/8] |=(1<<($1%8));$n", [rdLoc(idx), rdLoc(d),
rdSetElemLoc(a, e.typ), rdSetElemLoc(b, e.typ)]) rdSetElemLoc(a, e.typ), rdSetElemLoc(b, e.typ)])
else: else:
initLocExpr(p, e.sons[i], a) initLocExpr(p, e.sons[i], a)
appf(p.s[cpsStmts], "$1[$2/8] |=(1<<($2%8));$n", appf(p.s(cpsStmts), "$1[$2/8] |=(1<<($2%8));$n",
[rdLoc(d), rdSetElemLoc(a, e.typ)]) [rdLoc(d), rdSetElemLoc(a, e.typ)])
else: else:
# small set # small set
var ts = "NI" & $(getSize(e.typ) * 8) var ts = "NI" & $(getSize(e.typ) * 8)
appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(d)]) appf(p.s(cpsStmts), "$1 = 0;$n", [rdLoc(d)])
for i in countup(0, sonsLen(e) - 1): for i in countup(0, sonsLen(e) - 1):
if e.sons[i].kind == nkRange: if e.sons[i].kind == nkRange:
getTemp(p, getSysType(tyInt), idx) # our counter getTemp(p, getSysType(tyInt), idx) # our counter
initLocExpr(p, e.sons[i].sons[0], a) initLocExpr(p, e.sons[i].sons[0], a)
initLocExpr(p, e.sons[i].sons[1], b) initLocExpr(p, e.sons[i].sons[1], b)
appf(p.s[cpsStmts], "for ($1 = $3; $1 <= $4; $1++) $n" & appf(p.s(cpsStmts), "for ($1 = $3; $1 <= $4; $1++) $n" &
"$2 |=(1<<((" & ts & ")($1)%(sizeof(" & ts & ")*8)));$n", [ "$2 |=(1<<((" & ts & ")($1)%(sizeof(" & ts & ")*8)));$n", [
rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ), rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ),
rdSetElemLoc(b, e.typ)]) rdSetElemLoc(b, e.typ)])
else: else:
initLocExpr(p, e.sons[i], a) initLocExpr(p, e.sons[i], a)
appf(p.s[cpsStmts], appf(p.s(cpsStmts),
"$1 |=(1<<((" & ts & ")($2)%(sizeof(" & ts & ")*8)));$n", "$1 |=(1<<((" & ts & ")($2)%(sizeof(" & ts & ")*8)));$n",
[rdLoc(d), rdSetElemLoc(a, e.typ)]) [rdLoc(d), rdSetElemLoc(a, e.typ)])

View file

@ -280,7 +280,7 @@ proc mergeRequired*(m: BModule): bool =
#echo "not empty: ", i, " ", ropeToStr(m.s[i]) #echo "not empty: ", i, " ", ropeToStr(m.s[i])
return true return true
for i in low(TCProcSection)..high(TCProcSection): for i in low(TCProcSection)..high(TCProcSection):
if m.initProc.s[i] != nil: if m.initProc.s(i) != nil:
#echo "not empty: ", i, " ", ropeToStr(m.initProc.s[i]) #echo "not empty: ", i, " ", ropeToStr(m.initProc.s[i])
return true return true
@ -292,5 +292,5 @@ proc mergeFiles*(cfilename: string, m: BModule) =
for i in low(TCFileSection)..high(TCFileSection): for i in low(TCFileSection)..high(TCFileSection):
m.s[i] = con(old.f[i], m.s[i]) m.s[i] = con(old.f[i], m.s[i])
for i in low(TCProcSection)..high(TCProcSection): for i in low(TCProcSection)..high(TCProcSection):
m.initProc.s[i] = con(old.p[i], m.initProc.s[i]) m.initProc.s(i) = con(old.p[i], m.initProc.s(i))

View file

@ -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
@ -56,7 +101,15 @@ proc genSingleVar(p: BProc, a: PNode) =
if v.owner.kind != skModule: if v.owner.kind != skModule:
targetProc = p.module.preInitProc targetProc = p.module.preInitProc
assignGlobalVar(targetProc, v) assignGlobalVar(targetProc, v)
genObjectInit(targetProc, cpsInit, v.typ, v.loc, true) # XXX: be careful here.
# Global variables should not be zeromem-ed within loops
# (see bug #20).
# That's why we are doing the construction inside the preInitProc.
# genObjectInit relies on the C runtime's guarantees that
# global variables will be initialized to zero.
genObjectInit(p.module.preInitProc, cpsInit, v.typ, v.loc, true)
# Alternative construction using default constructor (which may zeromem):
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
else: else:
assignLocalVar(p, v) assignLocalVar(p, v)
initLocalVar(p, v, immediateAsgn) initLocalVar(p, v, immediateAsgn)
@ -110,16 +163,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:
#
var var
a: TLoc a: TLoc
Lelse: TLabel Lelse: TLabel
@ -132,15 +184,15 @@ proc genIfStmt(p: BProc, n: PNode) =
initLocExpr(p, it.sons[0], a) initLocExpr(p, it.sons[0], a)
Lelse = getLabel(p) Lelse = getLabel(p)
inc(p.labels) inc(p.labels)
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)
@ -169,7 +221,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
genLineDir(p, t) genLineDir(p, t)
if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0]) if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
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 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
@ -177,57 +229,46 @@ proc genWhileStmt(p: BProc, t: PNode) =
var var
a: TLoc a: TLoc
Labl: TLabel Labl: TLabel
length: int assert(sonsLen(t) == 2)
inc(p.withinLoop) inc(p.withinLoop)
genLineDir(p, t) genLineDir(p, t)
assert(sonsLen(t) == 2)
inc(p.labels) preserveBreakIdx:
Labl = con("LA", toRope(p.labels)) p.breakIdx = startBlock(p, "while (1) {$n")
length = len(p.blocks) initLocExpr(p, t.sons[0], a)
setlen(p.blocks, length + 1) if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
p.blocks[length].id = - p.labels # negative because it isn't used yet let label = assignLabel(p.blocks[p.breakIdx])
p.blocks[length].nestedTryStmts = p.nestedTryStmts.len appf(p.s(cpsStmts), "if (!$1) goto $2;$n", [rdLoc(a), label])
appf(p.s[cpsStmts], "while (1) {$n") genStmts(p, t.sons[1])
initLocExpr(p, t.sons[0], a) endBlock(p)
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
p.blocks[length].id = abs(p.blocks[length].id)
appf(p.s[cpsStmts], "if (!$1) goto $2;$n", [rdLoc(a), Labl])
genStmts(p, t.sons[1])
if p.blocks[length].id > 0: appf(p.s[cpsStmts], "} $1: ;$n", [Labl])
else: appf(p.s[cpsStmts], "}$n")
setlen(p.blocks, len(p.blocks) - 1)
dec(p.withinLoop) dec(p.withinLoop)
proc genBlock(p: BProc, t: PNode, d: var TLoc) = proc genBlock(p: BProc, t: PNode, d: var TLoc) =
inc(p.labels) preserveBreakIdx:
var idx = len(p.blocks) 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
setlen(p.blocks, idx + 1) if t.kind == nkBlockExpr: genStmtListExpr(p, t.sons[1], d)
p.blocks[idx].id = -p.labels # negative because it isn't used yet else: genStmts(p, t.sons[1])
p.blocks[idx].nestedTryStmts = p.nestedTryStmts.len endBlock(p)
if t.kind == nkBlockExpr: genStmtListExpr(p, t.sons[1], d)
else: genStmts(p, t.sons[1])
if p.blocks[idx].id > 0:
appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(p.blocks[idx].id)])
setlen(p.blocks, idx)
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)
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
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used 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)
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.blocks[idx].id)]) appf(p.s(cpsStmts), "goto $1;$n", [label])
proc getRaiseFrmt(p: BProc): string = proc getRaiseFrmt(p: BProc): string =
#if gCmd == cmdCompileToCpp: #if gCmd == cmdCompileToCpp:
@ -269,13 +310,13 @@ proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
proc genCaseSecondPass(p: BProc, t: PNode, labId, until: int): TLabel = proc genCaseSecondPass(p: BProc, t: PNode, labId, until: int): TLabel =
var Lend = getLabel(p) var Lend = getLabel(p)
for i in 1..until: for i in 1..until:
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,
@ -288,13 +329,13 @@ proc genIfForCaseUntil(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr,
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat, genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
con("LA", toRope(p.labels))) con("LA", toRope(p.labels)))
else: else:
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)]) appf(p.s(cpsStmts), "goto LA$1;$n", [toRope(p.labels)])
if until < t.len-1: if until < t.len-1:
inc(p.labels) inc(p.labels)
var gotoTarget = p.labels var gotoTarget = p.labels
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(gotoTarget)]) appf(p.s(cpsStmts), "goto LA$1;$n", [toRope(gotoTarget)])
result = genCaseSecondPass(p, t, labId, until) result = genCaseSecondPass(p, t, labId, until)
appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(gotoTarget)]) appf(p.s(cpsStmts), "LA$1: ;$n", [toRope(gotoTarget)])
else: else:
result = genCaseSecondPass(p, t, labId, until) result = genCaseSecondPass(p, t, labId, until)
@ -346,11 +387,11 @@ proc genStringCase(p: BProc, t: PNode) =
if interior != brn: if interior != brn:
echo "BUG! ", interior, "-", brn echo "BUG! ", interior, "-", brn
if branches[j] != nil: if branches[j] != nil:
appf(p.s[cpsStmts], "case $1: $n$2break;$n", appf(p.s(cpsStmts), "case $1: $n$2break;$n",
[intLiteral(j), branches[j]]) [intLiteral(j), branches[j]])
appf(p.s[cpsStmts], "}$n") # else statement: appf(p.s(cpsStmts), "}$n") # else statement:
if t.sons[sonsLen(t) - 1].kind != nkOfBranch: if t.sons[sonsLen(t) - 1].kind != nkOfBranch:
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)]) appf(p.s(cpsStmts), "goto LA$1;$n", [toRope(p.labels)])
# third pass: generate statements # third pass: generate statements
var Lend = genCaseSecondPass(p, t, labId, sonsLen(t)-1) var Lend = genCaseSecondPass(p, t, labId, sonsLen(t)-1)
fixLabel(p, Lend) fixLabel(p, Lend)
@ -379,16 +420,16 @@ proc genCaseRange(p: BProc, branch: PNode) =
for j in 0 .. length-2: for j in 0 .. length-2:
if branch[j].kind == nkRange: if branch[j].kind == nkRange:
if hasSwitchRange in CC[ccompiler].props: if hasSwitchRange in CC[ccompiler].props:
appf(p.s[cpsStmts], "case $1 ... $2:$n", [ appf(p.s(cpsStmts), "case $1 ... $2:$n", [
genLiteral(p, branch[j][0]), genLiteral(p, branch[j][0]),
genLiteral(p, branch[j][1])]) genLiteral(p, branch[j][1])])
else: else:
var v = copyNode(branch[j][0]) var v = copyNode(branch[j][0])
while v.intVal <= branch[j][1].intVal: while v.intVal <= branch[j][1].intVal:
appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, v)]) appf(p.s(cpsStmts), "case $1:$n", [genLiteral(p, v)])
Inc(v.intVal) Inc(v.intVal)
else: else:
appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, branch[j])]) appf(p.s(cpsStmts), "case $1:$n", [genLiteral(p, branch[j])])
proc genOrdinalCase(p: BProc, n: PNode) = proc genOrdinalCase(p: BProc, n: PNode) =
# analyse 'case' statement: # analyse 'case' statement:
@ -404,22 +445,22 @@ proc genOrdinalCase(p: BProc, n: PNode) =
# generate switch part (might be empty): # generate switch part (might be empty):
if splitPoint+1 < n.len: if splitPoint+1 < n.len:
appf(p.s[cpsStmts], "switch ($1) {$n", [rdCharLoc(a)]) appf(p.s(cpsStmts), "switch ($1) {$n", [rdCharLoc(a)])
var hasDefault = false var hasDefault = false
for i in splitPoint+1 .. < n.len: for i in splitPoint+1 .. < n.len:
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:
appf(p.s[cpsStmts], "default: __assume(0);$n") appf(p.s(cpsStmts), "default: __assume(0);$n")
appf(p.s[cpsStmts], "}$n") appf(p.s(cpsStmts), "}$n")
if Lend != nil: fixLabel(p, Lend) if Lend != nil: fixLabel(p, Lend)
proc genCaseStmt(p: BProc, t: PNode) = proc genCaseStmt(p: BProc, t: PNode) =
@ -466,6 +507,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
@ -475,42 +518,42 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
exc = getTempName() exc = getTempName()
if not hasGeneralExceptSection(t): if not hasGeneralExceptSection(t):
rethrowFlag = getTempName() rethrowFlag = getTempName()
appf(p.s[cpsLocals], "volatile NIM_BOOL $1 = NIM_FALSE;$n", [rethrowFlag]) appf(p.s(cpsLocals), "volatile NIM_BOOL $1 = NIM_FALSE;$n", [rethrowFlag])
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], "try {$n") appf(p.s(cpsStmts), "try {$n")
add(p.nestedTryStmts, t) add(p.nestedTryStmts, t)
genStmts(p, t.sons[0]) genStmts(p, t.sons[0])
length = sonsLen(t) length = sonsLen(t)
if t.sons[1].kind == nkExceptBranch: if t.sons[1].kind == nkExceptBranch:
appf(p.s[cpsStmts], "} catch (NimException& $1) {$n", [exc]) appf(p.s(cpsStmts), "} catch (NimException& $1) {$n", [exc])
if rethrowFlag != nil: if rethrowFlag != nil:
appf(p.s[cpsStmts], "$1 = NIM_TRUE;$n", [rethrowFlag]) appf(p.s(cpsStmts), "$1 = NIM_TRUE;$n", [rethrowFlag])
appf(p.s[cpsStmts], "if ($1.sp.exc) {$n", [exc]) appf(p.s(cpsStmts), "if ($1.sp.exc) {$n", [exc])
i = 1 i = 1
while (i < length) and (t.sons[i].kind == nkExceptBranch): while (i < length) and (t.sons[i].kind == nkExceptBranch):
blen = sonsLen(t.sons[i]) blen = sonsLen(t.sons[i])
if blen == 1: if blen == 1:
# general except section: # general except section:
appf(p.s[cpsStmts], "default:$n") appf(p.s(cpsStmts), "default:$n")
genStmts(p, t.sons[i].sons[0]) genStmts(p, t.sons[i].sons[0])
else: else:
for j in countup(0, blen - 2): for j in countup(0, blen - 2):
assert(t.sons[i].sons[j].kind == nkType) assert(t.sons[i].sons[j].kind == nkType)
appf(p.s[cpsStmts], "case $1:$n", [toRope(t.sons[i].sons[j].typ.id)]) appf(p.s(cpsStmts), "case $1:$n", [toRope(t.sons[i].sons[j].typ.id)])
genStmts(p, t.sons[i].sons[blen - 1]) genStmts(p, t.sons[i].sons[blen - 1])
if rethrowFlag != nil: if rethrowFlag != nil:
appf(p.s[cpsStmts], "$1 = NIM_FALSE; ", [rethrowFlag]) appf(p.s(cpsStmts), "$1 = NIM_FALSE; ", [rethrowFlag])
appf(p.s[cpsStmts], "break;$n") appf(p.s(cpsStmts), "break;$n")
inc(i) inc(i)
if t.sons[1].kind == nkExceptBranch: if t.sons[1].kind == nkExceptBranch:
appf(p.s[cpsStmts], "}}$n") # end of catch-switch statement appf(p.s(cpsStmts), "}}$n") # end of catch-switch statement
appcg(p, cpsStmts, "#popSafePoint();") appcg(p, cpsStmts, "#popSafePoint();")
discard pop(p.nestedTryStmts) discard pop(p.nestedTryStmts)
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]) genStmts(p, t.sons[i].sons[0])
if rethrowFlag != nil: if rethrowFlag != nil:
appf(p.s[cpsStmts], "if ($1) { throw; }$n", [rethrowFlag]) appf(p.s(cpsStmts), "if ($1) { throw; }$n", [rethrowFlag])
proc genTryStmt(p: BProc, t: PNode) = proc genTryStmt(p: BProc, t: PNode) =
# code to generate: # code to generate:
@ -531,10 +574,13 @@ proc genTryStmt(p: BProc, t: PNode) =
# clearException(); # clearException();
# } # }
# } # }
# /* finally: */ # {
# printf('fin!\n'); # /* finally: */
# printf('fin!\n');
# }
# if (exception not cleared) # if (exception not cleared)
# propagateCurrentException(); # propagateCurrentException();
#
genLineDir(p, t) genLineDir(p, t)
var safePoint = getTempName() var safePoint = getTempName()
discard cgsym(p.module, "E_Base") discard cgsym(p.module, "E_Base")
@ -543,24 +589,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
@ -570,17 +617,16 @@ proc genTryStmt(p: BProc, t: PNode) =
appcg(p.module, orExpr, appcg(p.module, orExpr,
"#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 =
@ -608,7 +654,7 @@ proc genAsmStmt(p: BProc, t: PNode) =
assert(t.kind == nkAsmStmt) assert(t.kind == nkAsmStmt)
genLineDir(p, t) genLineDir(p, t)
var s = genAsmOrEmitStmt(p, t) var s = genAsmOrEmitStmt(p, t)
appf(p.s[cpsStmts], CC[ccompiler].asmStmtFrmt, [s]) appf(p.s(cpsStmts), CC[ccompiler].asmStmtFrmt, [s])
proc genEmit(p: BProc, t: PNode) = proc genEmit(p: BProc, t: PNode) =
genLineDir(p, t) genLineDir(p, t)
@ -617,7 +663,7 @@ proc genEmit(p: BProc, t: PNode) =
# top level emit pragma? # top level emit pragma?
app(p.module.s[cfsProcHeaders], s) app(p.module.s[cfsProcHeaders], s)
else: else:
app(p.s[cpsStmts], s) app(p.s(cpsStmts), s)
var var
breakPointId: int = 0 breakPointId: int = 0

View file

@ -10,6 +10,8 @@
## Thread var support for crappy architectures that lack native support for ## Thread var support for crappy architectures that lack native support for
## thread local storage. (**Thank you Mac OS X!**) ## thread local storage. (**Thank you Mac OS X!**)
# included from cgen.nim
proc emulatedThreadVars(): bool {.inline.} = proc emulatedThreadVars(): bool {.inline.} =
result = {optThreads, optTlsEmulation} <= gGlobalOptions result = {optThreads, optTlsEmulation} <= gGlobalOptions
@ -17,8 +19,9 @@ proc AccessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars() and not p.ThreadVarAccessed: if emulatedThreadVars() and not p.ThreadVarAccessed:
p.ThreadVarAccessed = true p.ThreadVarAccessed = true
p.module.usesThreadVars = true p.module.usesThreadVars = true
appf(p.s[cpsLocals], "NimThreadVars* NimTV;$n") appf(p.procSec(cpsLocals), "NimThreadVars* NimTV;$n")
appcg(p, cpsInit, "NimTV=(NimThreadVars*)#GetThreadLocalVars();$n") app(p.procSec(cpsInit),
ropecg(p.module, "NimTV=(NimThreadVars*)#GetThreadLocalVars();$n"))
var var
nimtv: PRope # nimrod thread vars; the struct body nimtv: PRope # nimrod thread vars; the struct body

View file

@ -10,6 +10,8 @@
## Generates traversal procs for the C backend. Traversal procs are only an ## Generates traversal procs for the C backend. Traversal procs are only an
## optimization; the GC works without them too. ## optimization; the GC works without them too.
# included from cgen.nim
type type
TTraversalClosure {.pure, final.} = object TTraversalClosure {.pure, final.} = object
p: BProc p: BProc
@ -29,17 +31,17 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
if (n.sons[0].kind != nkSym): InternalError(n.info, "genTraverseProc") if (n.sons[0].kind != nkSym): InternalError(n.info, "genTraverseProc")
var p = c.p var p = c.p
let disc = n.sons[0].sym let disc = n.sons[0].sym
p.s[cpsStmts].appf("switch ($1.$2) {$n", accessor, disc.loc.r) p.s(cpsStmts).appf("switch ($1.$2) {$n", accessor, disc.loc.r)
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
let branch = n.sons[i] let branch = n.sons[i]
assert branch.kind in {nkOfBranch, nkElse} assert branch.kind in {nkOfBranch, nkElse}
if branch.kind == nkOfBranch: if branch.kind == nkOfBranch:
genCaseRange(c.p, branch) genCaseRange(c.p, branch)
else: else:
p.s[cpsStmts].appf("default:$n") p.s(cpsStmts).appf("default:$n")
genTraverseProc(c, accessor, lastSon(branch)) genTraverseProc(c, accessor, lastSon(branch))
p.s[cpsStmts].appf("break;$n") p.s(cpsStmts).appf("break;$n")
p.s[cpsStmts].appf("} $n") p.s(cpsStmts).appf("} $n")
of nkSym: of nkSym:
let field = n.sym let field = n.sym
genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t) genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t)
@ -61,10 +63,10 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
let arraySize = lengthOrd(typ.sons[0]) let arraySize = lengthOrd(typ.sons[0])
var i: TLoc var i: TLoc
getTemp(p, getSysType(tyInt), i) getTemp(p, getSysType(tyInt), i)
appf(p.s[cpsStmts], "for ($1 = 0; $1 < $2; $1++) {$n", appf(p.s(cpsStmts), "for ($1 = 0; $1 < $2; $1++) {$n",
i.r, arraySize.toRope) i.r, arraySize.toRope)
genTraverseProc(c, ropef("$1[$2]", accessor, i.r), typ.sons[1]) genTraverseProc(c, ropef("$1[$2]", accessor, i.r), typ.sons[1])
appf(p.s[cpsStmts], "}$n") appf(p.s(cpsStmts), "}$n")
of tyObject: of tyObject:
for i in countup(0, sonsLen(typ) - 1): for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, accessor.parentObj, typ.sons[i]) genTraverseProc(c, accessor.parentObj, typ.sons[i])
@ -87,10 +89,10 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
assert typ.kind == tySequence assert typ.kind == tySequence
var i: TLoc var i: TLoc
getTemp(p, getSysType(tyInt), i) getTemp(p, getSysType(tyInt), i)
appf(p.s[cpsStmts], "for ($1 = 0; $1 < $2->$3; $1++) {$n", appf(p.s(cpsStmts), "for ($1 = 0; $1 < $2->$3; $1++) {$n",
i.r, accessor, toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len")) i.r, accessor, toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len"))
genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0]) genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0])
appf(p.s[cpsStmts], "}$n") appf(p.s(cpsStmts), "}$n")
proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope = proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
var c: TTraversalClosure var c: TTraversalClosure
@ -104,8 +106,8 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
let header = ropef("N_NIMCALL(void, $1)(void* p, NI op)", result) let header = ropef("N_NIMCALL(void, $1)(void* p, NI op)", result)
let t = getTypeDesc(m, typ) let t = getTypeDesc(m, typ)
p.s[cpsLocals].appf("$1 a;$n", t) p.s(cpsLocals).appf("$1 a;$n", t)
p.s[cpsInit].appf("a = ($1)p;$n", t) p.s(cpsInit).appf("a = ($1)p;$n", t)
c.p = p c.p = p
if typ.kind == tySequence: if typ.kind == tySequence:
@ -118,7 +120,7 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
genTraverseProc(c, "(*a)".toRope, typ.sons[0]) genTraverseProc(c, "(*a)".toRope, typ.sons[0])
let generatedProc = ropef("$1 {$n$2$3$4}$n", let generatedProc = ropef("$1 {$n$2$3$4}$n",
[header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]]) [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
m.s[cfsProcHeaders].appf("$1;$n", header) m.s[cfsProcHeaders].appf("$1;$n", header)
m.s[cfsProcs].app(generatedProc) m.s[cfsProcs].app(generatedProc)

View file

@ -32,6 +32,15 @@ proc mangle(name: string): string =
add(result, "HEX") add(result, "HEX")
add(result, toHex(ord(name[i]), 2)) add(result, toHex(ord(name[i]), 2))
proc isCKeyword(w: PIdent): bool =
# nimrod and C++ share some keywords
# it's more efficient to test the whole nimrod keywords range
case w.id
of cppKeywordsLow..cppKeywordsHigh,
nimKeywordsLow..nimKeywordsHigh,
ord(wInline): return true
else: return false
proc mangleName(s: PSym): PRope = proc mangleName(s: PSym): PRope =
result = s.loc.r result = s.loc.r
if result == nil: if result == nil:
@ -45,9 +54,64 @@ proc mangleName(s: PSym): PRope =
of skTemp, skParam, skType, skEnumField, skModule: of skTemp, skParam, skType, skEnumField, skModule:
result = toRope("%") result = toRope("%")
else: InternalError(s.info, "mangleName") else: InternalError(s.info, "mangleName")
app(result, toRope(mangle(s.name.s))) when oKeepVariableNames:
app(result, "_") let keepOrigName = s.kind in skLocalVars - {skForVar} and
app(result, toRope(s.id)) {sfFromGeneric, sfGlobal, sfShadowed} * s.flags == {} and
not isCKeyword(s.name)
# XXX: This is still very experimental
#
# Even with all these inefficient checks, the bootstrap
# time is actually improved. This is probably because so many
# rope concatenations and are now eliminated.
#
# Future notes:
# sfFromGeneric seems to be needed in order to avoid multiple
# definitions of certain varialbes generated in transf with
# names such as:
# `r`, `res`
# I need to study where these come from.
#
# about sfShadowed:
# consider the following nimrod code:
# var x = 10
# block:
# var x = something(x)
# The generated C code will be:
# NI x;
# x = 10;
# {
# NI x;
# x = something(x); // Oops, x is already shadowed here
# }
# Right now, we work-around by not keeping the original name
# of the shadowed variable, but we can do better - we can
# create an alternative reference to it in the outer scope and
# use that in the inner scope.
#
# about isCKeyword:
# nimrod variable names can be C keywords.
# We need to avoid such names in the generated code.
# XXX: Study whether mangleName is called just once per variable.
# Otherwise, there might be better place to do this.
#
# about sfGlobal:
# This seems to be harder - a top level extern variable from
# another modules can have the same name as a local one.
# Maybe we should just implement sfShadowed for them too.
#
# about skForVar:
# These are not properly scoped now - we need to add blocks
# around for loops in transf
if keepOrigName:
result = s.name.s.toRope
else:
app(result, toRope(mangle(s.name.s)))
app(result, "_")
app(result, toRope(s.id))
else:
app(result, toRope(mangle(s.name.s)))
app(result, "_")
app(result, toRope(s.id))
s.loc.r = result s.loc.r = result
proc isCompileTimeOnly(t: PType): bool = proc isCompileTimeOnly(t: PType): bool =

View file

@ -151,7 +151,7 @@ proc appcg(m: BModule, s: TCFileSection, frmt: TFormatStr,
proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr, proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr,
args: openarray[PRope]) = args: openarray[PRope]) =
app(p.s[s], ropecg(p.module, frmt, args)) app(p.s(s), ropecg(p.module, frmt, args))
proc safeLineNm(info: TLineInfo): int = proc safeLineNm(info: TLineInfo): int =
result = toLinenumber(info) result = toLinenumber(info)
@ -168,14 +168,14 @@ proc genCLineDir(r: var PRope, info: TLineInfo) =
proc genLineDir(p: BProc, t: PNode) = proc genLineDir(p: BProc, t: PNode) =
var line = t.info.safeLineNm var line = t.info.safeLineNm
genCLineDir(p.s[cpsStmts], t.info.toFullPath, line) genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and
(p.prc == nil or sfPure notin p.prc.flags): (p.prc == nil or sfPure notin p.prc.flags):
appcg(p, cpsStmts, "#endb($1);$n", [toRope(line)]) appcg(p, cpsStmts, "#endb($1);$n", [toRope(line)])
elif ({optLineTrace, optStackTrace} * p.Options == elif ({optLineTrace, optStackTrace} * p.Options ==
{optLineTrace, optStackTrace}) and {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags): (p.prc == nil or sfPure notin p.prc.flags):
appf(p.s[cpsStmts], "F.line = $1;F.filename = $2;$n", appf(p.s(cpsStmts), "F.line = $1;F.filename = $2;$n",
[toRope(line), makeCString(toFilename(t.info).extractFilename)]) [toRope(line), makeCString(toFilename(t.info).extractFilename)])
include "ccgtypes.nim" include "ccgtypes.nim"
@ -229,45 +229,37 @@ proc isComplexValueType(t: PType): bool {.inline.} =
result = t.kind in {tyArray, tyArrayConstr, tySet, tyTuple, tyObject} or result = t.kind in {tyArray, tyArrayConstr, tySet, tyTuple, tyObject} or
(t.kind == tyProc and t.callConv == ccClosure) (t.kind == tyProc and t.callConv == ccClosure)
proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) = proc resetLoc(p: BProc, loc: var TLoc) =
let containsGcRef = containsGarbageCollectedRef(loc.t)
if not isComplexValueType(skipTypes(loc.t, abstractVarRange)): if not isComplexValueType(skipTypes(loc.t, abstractVarRange)):
if containsGcref and p.WithInLoop > 0: if containsGcRef:
appf(p.s[cpsInit], "$1 = 0;$n", [rdLoc(loc)])
var nilLoc: TLoc var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.t, onStack) initLoc(nilLoc, locTemp, loc.t, onStack)
nilLoc.r = toRope("NIM_NIL") nilLoc.r = toRope("NIM_NIL")
# puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
genRefAssign(p, loc, nilLoc, {afSrcIsNil}) genRefAssign(p, loc, nilLoc, {afSrcIsNil})
else: else:
appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)]) appf(p.s(cpsStmts), "$1 = 0;$n", [rdLoc(loc)])
else: else:
if containsGcref and p.WithInLoop > 0: if loc.s != OnStack:
appf(p.s[cpsInit], "memset((void*)$1, 0, sizeof($2));$n",
[addrLoc(loc), rdLoc(loc)])
genObjectInit(p, cpsInit, loc.t, loc, true)
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(loc), genTypeInfo(p.module, loc.t)]) [addrLoc(loc), genTypeInfo(p.module, loc.t)])
# XXX: generated reset procs should not touch the m_type
# field, so disabling this should be safe:
genObjectInit(p, cpsStmts, loc.t, loc, true)
else: else:
appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", appf(p.s(cpsStmts), "memset((void*)$1, 0, sizeof($2));$n",
[addrLoc(loc), rdLoc(loc)]) [addrLoc(loc), rdLoc(loc)])
# XXX: We can be extra clever here and call memset only
# on the bytes following the m_type field?
genObjectInit(p, cpsStmts, loc.t, loc, true) genObjectInit(p, cpsStmts, loc.t, loc, true)
proc zeroTemp(p: BProc, loc: TLoc) = proc constructLoc(p: BProc, loc: TLoc, section = cpsStmts) =
if not isComplexValueType(skipTypes(loc.t, abstractVarRange)): if not isComplexValueType(skipTypes(loc.t, abstractVarRange)):
appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)]) appf(p.s(section), "$1 = 0;$n", [rdLoc(loc)])
when false:
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.t, onStack)
nilLoc.r = toRope("NIM_NIL")
# puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
else: else:
appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", appf(p.s(section), "memset((void*)$1, 0, sizeof($2));$n",
[addrLoc(loc), rdLoc(loc)]) [addrLoc(loc), rdLoc(loc)])
# XXX no object init necessary for temporaries? genObjectInit(p, section, loc.t, loc, true)
when false:
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(loc), genTypeInfo(p.module, loc.t)])
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
if sfNoInit notin v.flags: if sfNoInit notin v.flags:
@ -279,11 +271,13 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
# ``var v = X()`` gets transformed into ``X(&v)``. # ``var v = X()`` gets transformed into ``X(&v)``.
# Nowadays the logic in ccgcalls deals with this case however. # Nowadays the logic in ccgcalls deals with this case however.
if not immediateAsgn: if not immediateAsgn:
zeroVar(p, v.loc, containsGarbageCollectedRef(v.typ)) constructLoc(p, v.loc)
proc initTemp(p: BProc, tmp: var TLoc) = proc initTemp(p: BProc, tmp: var TLoc) =
# XXX: This is still suspicious.
# Objects should always be constructed?
if containsGarbageCollectedRef(tmp.t) or isInvalidReturnType(tmp.t): if containsGarbageCollectedRef(tmp.t) or isInvalidReturnType(tmp.t):
zeroTemp(p, tmp) constructLoc(p, tmp)
proc getTemp(p: BProc, t: PType, result: var TLoc) = proc getTemp(p: BProc, t: PType, result: var TLoc) =
inc(p.labels) inc(p.labels)
@ -291,7 +285,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc) =
result.r = con("%LOC", toRope(p.labels)) result.r = con("%LOC", toRope(p.labels))
else: else:
result.r = con("LOC", toRope(p.labels)) result.r = con("LOC", toRope(p.labels))
appf(p.s[cpsLocals], "$1 $2;$n", [getTypeDesc(p.module, t), result.r]) appf(p.s(cpsLocals), "$1 $2;$n", [getTypeDesc(p.module, t), result.r])
result.k = locTemp result.k = locTemp
result.a = - 1 result.a = - 1
result.t = getUniqueType(t) result.t = getUniqueType(t)
@ -361,7 +355,7 @@ proc allocParam(p: BProc, s: PSym) =
var tmp = con("%LOC", toRope(p.labels)) var tmp = con("%LOC", toRope(p.labels))
incl(s.loc.flags, lfParamCopy) incl(s.loc.flags, lfParamCopy)
incl(s.loc.flags, lfIndirect) incl(s.loc.flags, lfIndirect)
appf(p.s[cpsInit], "$1 = alloca $3$n" & "store $3 $2, $3* $1$n", appf(p.s(cpsInit), "$1 = alloca $3$n" & "store $3 $2, $3* $1$n",
[tmp, s.loc.r, getTypeDesc(p.module, s.loc.t)]) [tmp, s.loc.r, getTypeDesc(p.module, s.loc.t)])
s.loc.r = tmp s.loc.r = tmp
@ -371,7 +365,7 @@ proc localDebugInfo(p: BProc, s: PSym) =
if skipTypes(s.typ, abstractVar).kind == tyOpenArray: return if skipTypes(s.typ, abstractVar).kind == tyOpenArray: return
var a = con("&", s.loc.r) var a = con("&", s.loc.r)
if (s.kind == skParam) and ccgIntroducedPtr(s): a = s.loc.r if (s.kind == skParam) and ccgIntroducedPtr(s): a = s.loc.r
appf(p.s[cpsInit], appf(p.s(cpsInit),
"F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n", "F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
[toRope(p.frameLen), makeCString(normalize(s.name.s)), a, [toRope(p.frameLen), makeCString(normalize(s.name.s)), a,
genTypeInfo(p.module, s.loc.t)]) genTypeInfo(p.module, s.loc.t)])
@ -384,13 +378,13 @@ proc assignLocalVar(p: BProc, s: PSym) =
if s.loc.k == locNone: if s.loc.k == locNone:
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack) fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t)) app(p.s(cpsLocals), getTypeDesc(p.module, s.loc.t))
if sfRegister in s.flags: app(p.s[cpsLocals], " register") if sfRegister in s.flags: app(p.s(cpsLocals), " register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# app(p.s[cpsLocals], " GC_GUARD") # app(p.s[cpsLocals], " GC_GUARD")
if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0): if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0):
app(p.s[cpsLocals], " volatile") app(p.s(cpsLocals), " volatile")
appf(p.s[cpsLocals], " $1;$n", [s.loc.r]) appf(p.s(cpsLocals), " $1;$n", [s.loc.r])
localDebugInfo(p, s) localDebugInfo(p, s)
include ccgthreadvars include ccgthreadvars
@ -410,7 +404,7 @@ proc assignGlobalVar(p: BProc, s: PSym) =
appf(p.module.s[cfsVars], " $1;$n", [s.loc.r]) appf(p.module.s[cfsVars], " $1;$n", [s.loc.r])
if p.withinLoop > 0: if p.withinLoop > 0:
# fixes tests/run/tzeroarray: # fixes tests/run/tzeroarray:
initLocalVar(p, s, false) resetLoc(p, s.loc)
if p.module.module.options * {optStackTrace, optEndb} == if p.module.module.options * {optStackTrace, optEndb} ==
{optStackTrace, optEndb}: {optStackTrace, optEndb}:
appcg(p.module, p.module.s[cfsDebugInit], appcg(p.module, p.module.s[cfsDebugInit],
@ -433,7 +427,7 @@ proc getLabel(p: BProc): TLabel =
result = con("LA", toRope(p.labels)) result = con("LA", toRope(p.labels))
proc fixLabel(p: BProc, labl: TLabel) = proc fixLabel(p: BProc, labl: TLabel) =
appf(p.s[cpsStmts], "$1: ;$n", [labl]) appf(p.s(cpsStmts), "$1: ;$n", [labl])
proc genVarPrototype(m: BModule, sym: PSym) proc genVarPrototype(m: BModule, sym: PSym)
proc requestConstImpl(p: BProc, sym: PSym) proc requestConstImpl(p: BProc, sym: PSym)
@ -481,9 +475,9 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
var p = newProc(nil, m) var p = newProc(nil, m)
var dest: TLoc var dest: TLoc
initLocExpr(p, lib.path, dest) initLocExpr(p, lib.path, dest)
app(m.s[cfsVars], p.s[cpsLocals]) app(m.s[cfsVars], p.s(cpsLocals))
app(m.s[cfsDynLibInit], p.s[cpsInit]) app(m.s[cfsDynLibInit], p.s(cpsInit))
app(m.s[cfsDynLibInit], p.s[cpsStmts]) app(m.s[cfsDynLibInit], p.s(cpsStmts))
appcg(m, m.s[cfsDynLibInit], appcg(m, m.s[cfsDynLibInit],
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n", "if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
[tmp, rdLoc(dest)]) [tmp, rdLoc(dest)])
@ -551,13 +545,13 @@ proc getFrameDecl(p: BProc) =
[toRope(p.frameLen)]) [toRope(p.frameLen)])
else: else:
slots = nil slots = nil
appff(p.s[cpsLocals], "volatile struct {TFrame* prev;" & appff(p.s(cpsLocals), "volatile struct {TFrame* prev;" &
"NCSTRING procname;NI line;NCSTRING filename;" & "NCSTRING procname;NI line;NCSTRING filename;" &
"NI len;$n$1} F;$n", "NI len;$n$1} F;$n",
"%TF = type {%TFrame*, i8*, %NI, %NI$1}$n" & "%TF = type {%TFrame*, i8*, %NI, %NI$1}$n" &
"%F = alloca %TF$n", [slots]) "%F = alloca %TF$n", [slots])
inc(p.labels) inc(p.labels)
prepend(p.s[cpsInit], ropeff("F.len = $1;$n", prepend(p.s(cpsInit), ropeff("F.len = $1;$n",
"%LOC$2 = getelementptr %TF %F, %NI 4$n" & "%LOC$2 = getelementptr %TF %F, %NI 4$n" &
"store %NI $1, %NI* %LOC$2$n", [toRope(p.frameLen), toRope(p.labels)])) "store %NI $1, %NI* %LOC$2$n", [toRope(p.frameLen), toRope(p.labels)]))
@ -613,32 +607,32 @@ proc genProcAux(m: BModule, prc: PSym) =
var generatedProc: PRope var generatedProc: PRope
if sfPure in prc.flags: if sfPure in prc.flags:
generatedProc = ropeff("$1 {$n$2$3$4}$n", "define $1 {$n$2$3$4}$n", generatedProc = ropeff("$1 {$n$2$3$4}$n", "define $1 {$n$2$3$4}$n",
[header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]]) [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
else: else:
generatedProc = ropeff("$1 {$n", "define $1 {$n", [header]) generatedProc = ropeff("$1 {$n", "define $1 {$n", [header])
app(generatedProc, initGCFrame(p)) app(generatedProc, initGCFrame(p))
if optStackTrace in prc.options: if optStackTrace in prc.options:
getFrameDecl(p) getFrameDecl(p)
app(generatedProc, p.s[cpsLocals]) app(generatedProc, p.s(cpsLocals))
var procname = CStringLit(p, generatedProc, prc.name.s) var procname = CStringLit(p, generatedProc, prc.name.s)
var filename = CStringLit(p, generatedProc, toFilename(prc.info)) var filename = CStringLit(p, generatedProc, toFilename(prc.info))
app(generatedProc, initFrame(p, procname, filename)) app(generatedProc, initFrame(p, procname, filename))
else: else:
app(generatedProc, p.s[cpsLocals]) app(generatedProc, p.s(cpsLocals))
if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM): if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM):
if gProcProfile >= 64 * 1024: if gProcProfile >= 64 * 1024:
InternalError(prc.info, "too many procedures for profiling") InternalError(prc.info, "too many procedures for profiling")
discard cgsym(m, "profileData") discard cgsym(m, "profileData")
appf(p.s[cpsLocals], "ticks NIM_profilingStart;$n") appf(p.s(cpsLocals), "ticks NIM_profilingStart;$n")
if prc.loc.a < 0: if prc.loc.a < 0:
appf(m.s[cfsDebugInit], "profileData[$1].procname = $2;$n", [ appf(m.s[cfsDebugInit], "profileData[$1].procname = $2;$n", [
toRope(gProcProfile), toRope(gProcProfile),
makeCString(prc.name.s)]) makeCString(prc.name.s)])
prc.loc.a = gProcProfile prc.loc.a = gProcProfile
inc(gProcProfile) inc(gProcProfile)
prepend(p.s[cpsInit], ropef("NIM_profilingStart = getticks();$n")) prepend(p.s(cpsInit), ropef("NIM_profilingStart = getticks();$n"))
app(generatedProc, p.s[cpsInit]) app(generatedProc, p.s(cpsInit))
app(generatedProc, p.s[cpsStmts]) app(generatedProc, p.s(cpsStmts))
if p.beforeRetNeeded: appf(generatedProc, "BeforeRet: $n;") if p.beforeRetNeeded: appf(generatedProc, "BeforeRet: $n;")
app(generatedProc, deinitGCFrame(p)) app(generatedProc, deinitGCFrame(p))
if optStackTrace in prc.options: app(generatedProc, deinitFrame(p)) if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
@ -858,8 +852,8 @@ proc genInitCode(m: BModule) =
app(prc, initGCFrame(m.initProc)) app(prc, initGCFrame(m.initProc))
app(prc, genSectionStart(cpsLocals)) app(prc, genSectionStart(cpsLocals))
app(prc, m.initProc.s[cpsLocals]) app(prc, m.initProc.s(cpsLocals))
app(prc, m.preInitProc.s[cpsLocals]) app(prc, m.preInitProc.s(cpsLocals))
app(prc, genSectionEnd(cpsLocals)) app(prc, genSectionEnd(cpsLocals))
app(prc, genSectionStart(cfsTypeInit1)) app(prc, genSectionStart(cfsTypeInit1))
@ -876,13 +870,13 @@ proc genInitCode(m: BModule) =
app(prc, genSectionEnd(i)) app(prc, genSectionEnd(i))
app(prc, genSectionStart(cpsInit)) app(prc, genSectionStart(cpsInit))
app(prc, m.preInitProc.s[cpsInit]) app(prc, m.preInitProc.s(cpsInit))
app(prc, m.initProc.s[cpsInit]) app(prc, m.initProc.s(cpsInit))
app(prc, genSectionEnd(cpsInit)) app(prc, genSectionEnd(cpsInit))
app(prc, genSectionStart(cpsStmts)) app(prc, genSectionStart(cpsStmts))
app(prc, m.preInitProc.s[cpsStmts]) app(prc, m.preInitProc.s(cpsStmts))
app(prc, m.initProc.s[cpsStmts]) app(prc, m.initProc.s(cpsStmts))
if optStackTrace in m.initProc.options and not m.PreventStackTrace: if optStackTrace in m.initProc.options and not m.PreventStackTrace:
app(prc, deinitFrame(m.initProc)) app(prc, deinitFrame(m.initProc))
app(prc, genSectionEnd(cpsStmts)) app(prc, genSectionEnd(cpsStmts))

View file

@ -48,13 +48,14 @@ type
TCProcSections* = array[TCProcSection, PRope] # represents a generated C proc TCProcSections* = array[TCProcSection, PRope] # represents a generated C proc
BModule* = ref TCGen BModule* = ref TCGen
BProc* = ref TCProc BProc* = ref TCProc
TBlock{.final.} = object TBlock*{.final.} = object
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) label*: PRope # generated text for the label
# 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
TCProc{.final.} = object # represents C proc that is currently generated TCProc{.final.} = object # represents C proc that is currently generated
s*: TCProcSections # the procs sections; short name for readability
prc*: PSym # the Nimrod proc that this C proc belongs to prc*: PSym # the Nimrod proc that this C proc belongs to
BeforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed BeforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
ThreadVarAccessed*: bool # true if the proc already accessed some threadvar ThreadVarAccessed*: bool # true if the proc already accessed some threadvar
@ -64,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
@ -113,6 +116,13 @@ var
gForwardedProcsCounter*: int = 0 gForwardedProcsCounter*: int = 0
gNimDat*: BModule # generated global data gNimDat*: BModule # generated global data
proc s*(p: BProc, s: TCProcSection): var PRope {.inline.} =
# section in the current block
result = p.blocks[p.blocks.len - 1].sections[s]
proc procSec*(p: BProc, s: TCProcSection): var PRope {.inline.} =
# top level proc sections
result = p.blocks[0].sections[s]
proc newProc*(prc: PSym, module: BModule): BProc = proc newProc*(prc: PSym, module: BModule): BProc =
new(result) new(result)
@ -120,6 +130,6 @@ proc newProc*(prc: PSym, module: BModule): BProc =
result.module = module result.module = module
if prc != nil: result.options = prc.options if prc != nil: result.options = prc.options
else: result.options = gOptions else: result.options = gOptions
result.blocks = @[] newSeq(result.blocks, 1)
result.nestedTryStmts = @[] result.nestedTryStmts = @[]

View file

@ -114,6 +114,8 @@ var
implicitImports*: seq[string] = @[] # modules that are to be implicitly imported implicitImports*: seq[string] = @[] # modules that are to be implicitly imported
implicitIncludes*: seq[string] = @[] # modules that are to be implicitly included implicitIncludes*: seq[string] = @[] # modules that are to be implicitly included
const oKeepVariableNames* = true
proc mainCommandArg*: string = proc mainCommandArg*: string =
## This is intended for commands like check or parse ## This is intended for commands like check or parse
## which will work on the main project file unless ## which will work on the main project file unless

View file

@ -62,6 +62,7 @@ type
AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
# store this info in the syms themselves!) # store this info in the syms themselves!)
InGenericContext*: int # > 0 if we are in a generic InGenericContext*: int # > 0 if we are in a generic
InUnrolledContext*: int # > 0 if we are unrolling a loop
converters*: TSymSeq # sequence of converters converters*: TSymSeq # sequence of converters
optionStack*: TLinkedList optionStack*: TLinkedList
libs*: TLinkedList # all libs used by this module libs*: TLinkedList # all libs used by this module

View file

@ -15,6 +15,8 @@
# So we have to eval templates/macros right here so that symbol # So we have to eval templates/macros right here so that symbol
# lookup can be accurate. # lookup can be accurate.
# included from sem.nim
type type
TSemGenericFlag = enum TSemGenericFlag = enum
withinBind, withinTypeDesc withinBind, withinTypeDesc

View file

@ -50,8 +50,8 @@ proc semIf(c: PContext, n: PNode): PNode =
case it.kind case it.kind
of nkElifBranch: of nkElifBranch:
checkSonsLen(it, 2) checkSonsLen(it, 2)
openScope(c.tab)
it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0])) it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
openScope(c.tab)
it.sons[1] = semStmt(c, it.sons[1]) it.sons[1] = semStmt(c, it.sons[1])
closeScope(c.tab) closeScope(c.tab)
of nkElse: of nkElse:
@ -217,6 +217,12 @@ proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
elif not sameType(result.typ, typ): elif not sameType(result.typ, typ):
changeType(result, typ) changeType(result, typ)
proc findShadowedVar(c: PContext, v: PSym): PSym =
for i in countdown(c.tab.tos - 2, 0):
let shadowed = StrTableGet(c.tab.stack[i], v.name)
if shadowed != nil and shadowed.kind in skLocalVars:
return shadowed
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
if isTopLevel(c): if isTopLevel(c):
result = semIdentWithPragma(c, kind, n, {sfExported}) result = semIdentWithPragma(c, kind, n, {sfExported})
@ -267,6 +273,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
for j in countup(0, length-3): for j in countup(0, length-3):
var v = semIdentDef(c, a.sons[j], symkind) var v = semIdentDef(c, a.sons[j], symkind)
addInterfaceDecl(c, v) addInterfaceDecl(c, v)
when oKeepVariableNames:
if c.InUnrolledContext > 0: v.flags.incl(sfShadowed)
else:
let shadowed = findShadowedVar(c, v)
if shadowed != nil: shadowed.flags.incl(sfShadowed)
if def != nil and def.kind != nkEmpty: if def != nil and def.kind != nkEmpty:
# this is only needed for the evaluation pass: # this is only needed for the evaluation pass:
v.ast = def v.ast = def
@ -392,7 +403,9 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
openScope(c.tab) openScope(c.tab)
var body = transfFieldLoopBody(loopBody, n, tupleTypeA, i, var body = transfFieldLoopBody(loopBody, n, tupleTypeA, i,
ord(m==mFieldPairs)) ord(m==mFieldPairs))
inc c.InUnrolledContext
stmts.add(SemStmt(c, body)) stmts.add(SemStmt(c, body))
dec c.InUnrolledContext
closeScope(c.tab) closeScope(c.tab)
Dec(c.p.nestedLoopCounter) Dec(c.p.nestedLoopCounter)
var b = newNodeI(nkBreakStmt, n.info) var b = newNodeI(nkBreakStmt, n.info)

View file

@ -38,8 +38,8 @@ type
wMagic, wThread, wFinal, wProfiler, wObjChecks, wMagic, wThread, wFinal, wProfiler, wObjChecks,
wImmediate, wImportCpp, wImportObjC, wImmediate, wImportCpp, wImportObjC,
wImportCompilerProc, wImportCompilerProc,
wImportc, wExportc, wExtern, wIncompleteStruct, wImportc, wExportc, wIncompleteStruct,
wAlign, wNodecl, wPure, wVolatile, wRegister, wSideeffect, wHeader, wAlign, wNodecl, wPure, wSideeffect, wHeader,
wNosideeffect, wNoreturn, wMerge, wLib, wDynlib, wCompilerproc, wProcVar, wNosideeffect, wNoreturn, wMerge, wLib, wDynlib, wCompilerproc, wProcVar,
wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef, wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef,
wLinedir, wStacktrace, wLinetrace, wLink, wCompile, wLinedir, wStacktrace, wLinetrace, wLink, wCompile,
@ -58,13 +58,36 @@ type
wWatchPoint, wSubsChar, wWatchPoint, wSubsChar,
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wAcyclic, wShallow, wUnroll, wLinearScanEnd,
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame, wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame,
wImplicitStatic, wGlobal wImplicitStatic, wGlobal,
wAuto, wBool, wCatch, wChar, wClass,
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
wExplicit, wExtern, wFalse, wFloat, wFriend,
wGoto, wInt, wLong, wMutable, wNamespace, wNew, wOperator,
wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast,
wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch,
wThis, wThrow, wTrue, wTypedef, wTypeid, wTypename,
wUnion, wUnsigned, wUsing, wVirtual, wVoid, wVolatile, wWchar_t,
wAlignas, wAlignof, wConstexpr, wDecltype, wNullptr, wNoexcept,
wThread_local, wStatic_assert, wChar16_t, wChar32_t,
TSpecialWords* = set[TSpecialWord] TSpecialWords* = set[TSpecialWord]
const const
oprLow* = ord(wColon) oprLow* = ord(wColon)
oprHigh* = ord(wDotDot) oprHigh* = ord(wDotDot)
nimKeywordsLow* = ord(wAsm)
nimKeywordsHigh* = ord(wYield)
cppKeywordsLow* = ord(wAuto)
cppKeywordsHigh* = ord(wChar32_t)
cppNimSharedKeywords* = {
wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport,
wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile }
specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["", specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["",
"addr", "and", "as", "asm", "atomic", "addr", "and", "as", "asm", "atomic",
@ -86,8 +109,8 @@ const
"magic", "thread", "final", "profiler", "objchecks", "magic", "thread", "final", "profiler", "objchecks",
"immediate", "importcpp", "importobjc", "immediate", "importcpp", "importobjc",
"importcompilerproc", "importc", "exportc", "extern", "incompletestruct", "importcompilerproc", "importc", "exportc", "incompletestruct",
"align", "nodecl", "pure", "volatile", "register", "sideeffect", "align", "nodecl", "pure", "sideeffect",
"header", "nosideeffect", "noreturn", "merge", "lib", "dynlib", "header", "nosideeffect", "noreturn", "merge", "lib", "dynlib",
"compilerproc", "procvar", "fatal", "error", "warning", "hint", "line", "compilerproc", "procvar", "fatal", "error", "warning", "hint", "line",
"push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace", "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace",
@ -107,7 +130,22 @@ const
"watchpoint", "watchpoint",
"subschar", "acyclic", "shallow", "unroll", "linearscanend", "subschar", "acyclic", "shallow", "unroll", "linearscanend",
"write", "putenv", "prependenv", "appendenv", "threadvar", "emit", "write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
"nostackframe", "implicitstatic", "global"] "nostackframe", "implicitstatic", "global",
"auto", "bool", "catch", "char", "class",
"const_cast", "default", "delete", "double",
"dynamic_cast", "explicit", "extern", "false",
"float", "friend", "goto", "int", "long", "mutable",
"namespace", "new", "operator",
"private", "protected", "public", "register", "reinterpret_cast",
"short", "signed", "sizeof", "static_cast", "struct", "switch",
"this", "throw", "true", "typedef", "typeid",
"typename", "union", "unsigned", "using", "virtual", "void", "volatile",
"wchar_t",
"alignas", "alignof", "constexpr", "decltype", "nullptr", "noexcept",
"thread_local", "static_assert", "char16_t", "char32_t",
]
proc findStr*(a: openarray[string], s: string): int = proc findStr*(a: openarray[string], s: string): int =
for i in countup(low(a), high(a)): for i in countup(low(a), high(a)):

View file

@ -30,18 +30,13 @@ template colorOp(op: expr) {.immediate.} =
extract(b, br, bg, bb) extract(b, br, bg, bb)
result = rawRGB(op(ar, br), op(ag, bg), op(ab, bb)) result = rawRGB(op(ar, br), op(ag, bg), op(ab, bb))
template satPlus(a, b: expr): expr = proc satPlus(a, b: int): int {.inline.} =
# saturated plus: result = a +% b
block: if result > 255: result = 255
var result = a +% b
if result > 255: result = 255
result
template satMinus(a, b: expr): expr = proc satMinus(a, b: int): int {.inline.} =
block: result = a -% b
var result = a -% b if result < 0: result = 0
if result < 0: result = 0
result
proc `+`*(a, b: TColor): TColor = proc `+`*(a, b: TColor): TColor =
## adds two colors: This uses saturated artithmetic, so that each color ## adds two colors: This uses saturated artithmetic, so that each color

View file

@ -1738,7 +1738,6 @@ when isMainModule:
else: else:
assert false assert false
var matches: array[0..5, string]
if match("abcdefg", peg"c {d} ef {g}", matches, 2): if match("abcdefg", peg"c {d} ef {g}", matches, 2):
assert matches[0] == "d" assert matches[0] == "d"
assert matches[1] == "g" assert matches[1] == "g"

View file

@ -1593,12 +1593,12 @@ 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)
e.msg = message e.msg = message
e e
when not defined(EcmaScript) and not defined(NimrodVM): when not defined(EcmaScript) and not defined(NimrodVM):
{.push stack_trace: off.} {.push stack_trace: off.}

View file

@ -1734,7 +1734,6 @@ when isMainModule:
else: else:
doAssert false doAssert false
var matches: array[0..5, string]
if match("abcdefg", peg"c {d} ef {g}", matches, 2): if match("abcdefg", peg"c {d} ef {g}", matches, 2):
doAssert matches[0] == "d" doAssert matches[0] == "d"
doAssert matches[1] == "g" doAssert matches[1] == "g"

View file

@ -10,20 +10,21 @@
## Include for the tester that contains test suites that test special features ## Include for the tester that contains test suites that test special features
## of the compiler. ## of the compiler.
# included from tester.nim
# ---------------- ROD file tests --------------------------------------------- # ---------------- ROD file tests ---------------------------------------------
const const
rodfilesDir = "tests/rodfiles" rodfilesDir = "tests/rodfiles"
nimcacheDir = rodfilesDir / "nimcache"
proc delNimCache() = proc delNimCache() =
let dir = rodfilesDir / "nimcache"
try: try:
removeDir(dir) removeDir(nimcacheDir)
except EOS: except EOS:
echo "[Warning] could not delete: ", dir echo "[Warning] could not delete: ", nimcacheDir
proc plusCache(options: string): string = return options & proc plusCache(options: string): string = return options &
" --symbolFiles:on --nimcache:./nimcache" " --symbolFiles:on --nimcache:" & nimcacheDir
proc runRodFiles(r: var TResults, options: string) = proc runRodFiles(r: var TResults, options: string) =
template test(filename: expr): stmt = template test(filename: expr): stmt =