don't generate memset calls for C++ objects

This commit is contained in:
Araq
2015-03-17 21:36:40 +01:00
parent ca22dfcdc2
commit 1fc590b6ea
5 changed files with 448 additions and 440 deletions

View File

@@ -33,7 +33,7 @@ proc isAssignedImmediately(n: PNode): bool {.inline.} =
return false
result = true
proc genVarTuple(p: BProc, n: PNode) =
proc genVarTuple(p: BProc, n: PNode) =
var tup, field: TLoc
if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
var L = sonsLen(n)
@@ -49,7 +49,7 @@ proc genVarTuple(p: BProc, n: PNode) =
genLineDir(p, n)
initLocExpr(p, n.sons[L-1], tup)
var t = tup.t.getUniqueType
for i in countup(0, L-3):
for i in countup(0, L-3):
var v = n.sons[i].sym
if sfCompileTime in v.flags: continue
if sfGlobal in v.flags:
@@ -60,11 +60,11 @@ proc genVarTuple(p: BProc, n: PNode) =
assignLocalVar(p, v)
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(n[L-1]))
initLoc(field, locExpr, t.sons[i], tup.s)
if t.kind == tyTuple:
if t.kind == tyTuple:
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
else:
else:
if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
field.r = ropef("$1.$2",
field.r = ropef("$1.$2",
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
putLocIntoDest(p, v.loc, field)
@@ -117,7 +117,7 @@ proc endBlock(p: BProc, blockEnd: PRope) =
line(p, cpsStmts, blockEnd)
proc endBlock(p: BProc) =
let topBlock = p.blocks.len - 1
let topBlock = p.blocks.len - 1
var blockEnd = if p.blocks[topBlock].label != nil:
rfmt(nil, "} $1: ;$n", p.blocks[topBlock].label)
else:
@@ -190,10 +190,10 @@ proc genSingleVar(p: BProc, a: PNode) =
targetProc = p.module.preInitProc
assignGlobalVar(targetProc, v)
# XXX: be careful here.
# Global variables should not be zeromem-ed within loops
# 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
# 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):
@@ -229,10 +229,10 @@ proc genClosureVar(p: BProc, a: PNode) =
genLineDir(p, a)
loadInto(p, a.sons[0], a.sons[2], v)
proc genVarStmt(p: BProc, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
proc genVarStmt(p: BProc, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if a.kind == nkCommentStmt: continue
if a.kind == nkIdentDefs:
# can be a lifted var nowadays ...
if a.sons[0].kind == nkSym:
@@ -242,12 +242,12 @@ proc genVarStmt(p: BProc, n: PNode) =
else:
genVarTuple(p, a)
proc genConstStmt(p: BProc, t: PNode) =
for i in countup(0, sonsLen(t) - 1):
proc genConstStmt(p: BProc, t: PNode) =
for i in countup(0, sonsLen(t) - 1):
var it = t.sons[i]
if it.kind == nkCommentStmt: continue
if it.kind == nkCommentStmt: continue
if it.kind != nkConstDef: internalError(t.info, "genConstStmt")
var c = it.sons[0].sym
var c = it.sons[0].sym
if c.typ.containsCompileTimeOnly: continue
if sfFakeConst in c.flags:
genSingleVar(p, it)
@@ -274,9 +274,9 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
getTemp(p, n.typ, d)
genLineDir(p, n)
let lend = getLabel(p)
for i in countup(0, sonsLen(n) - 1):
for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i]
if it.len == 2:
if it.len == 2:
when newScopeForIf: startBlock(p)
initLocExprSingleUse(p, it.sons[0], a)
lelse = getLabel(p)
@@ -303,13 +303,13 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
if sonsLen(n) > 1: fixLabel(p, lend)
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
# Called by return and break stmts.
# Deals with issues faced when jumping out of try/except/finally stmts,
var stack: seq[PNode]
newSeq(stack, 0)
var alreadyPoppedCnt = p.inExceptBlock
for i in countup(1, howManyTrys):
if not p.module.compileToCpp:
@@ -327,11 +327,11 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
# Find finally-stmt for this try-stmt
# and generate a copy of its sons
var finallyStmt = lastSon(tryStmt)
if finallyStmt.kind == nkFinally:
if finallyStmt.kind == nkFinally:
genStmts(p, finallyStmt.sons[0])
# push old elements again:
for i in countdown(howManyTrys-1, 0):
for i in countdown(howManyTrys-1, 0):
p.nestedTryStmts.add(stack[i])
if not p.module.compileToCpp:
@@ -344,14 +344,14 @@ proc genReturnStmt(p: BProc, t: PNode) =
p.beforeRetNeeded = true
genLineDir(p, t)
if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
blockLeaveActions(p,
blockLeaveActions(p,
howManyTrys = p.nestedTryStmts.len,
howManyExcepts = p.inExceptBlock)
if (p.finallySafePoints.len > 0):
# If we're in a finally block, and we came here by exception
# consume it before we return.
var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
lineF(p, cpsStmts, "goto BeforeRet;$n", [])
proc genComputedGoto(p: BProc; n: PNode) =
@@ -387,7 +387,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
let topBlock = p.blocks.len-1
let oldBody = p.blocks[topBlock].sections[cpsStmts]
p.blocks[topBlock].sections[cpsStmts] = nil
for j in casePos+1 .. <n.len: genStmts(p, n.sons[j])
let tailB = p.blocks[topBlock].sections[cpsStmts]
@@ -402,7 +402,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
initLocExpr(p, caseStmt.sons[0], a)
# first goto:
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
for i in 1 .. <caseStmt.len:
startBlock(p)
let it = caseStmt.sons[i]
@@ -426,7 +426,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
proc genWhileStmt(p: BProc, t: PNode) =
# we don't generate labels here as for example GCC would produce
# significantly worse code
var
var
a: TLoc
labl: TLabel
assert(sonsLen(t) == 2)
@@ -437,7 +437,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
p.breakIdx = startBlock(p, "while (1) {$n")
p.blocks[p.breakIdx].isLoop = true
initLocExpr(p, t.sons[0], a)
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
let label = assignLabel(p.blocks[p.breakIdx])
lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
var loopBody = t.sons[1]
@@ -483,23 +483,23 @@ proc genParForStmt(p: BProc, t: PNode) =
let call = t.sons[1]
initLocExpr(p, call.sons[1], rangeA)
initLocExpr(p, call.sons[2], rangeB)
lineF(p, cpsStmts, "#pragma omp parallel for $4$n" &
"for ($1 = $2; $1 <= $3; ++$1)",
"for ($1 = $2; $1 <= $3; ++$1)",
forLoopVar.loc.rdLoc,
rangeA.rdLoc, rangeB.rdLoc,
call.sons[3].getStr.toRope)
p.breakIdx = startBlock(p)
p.blocks[p.breakIdx].isLoop = true
genStmts(p, t.sons[2])
endBlock(p)
dec(p.withinLoop)
proc genBreakStmt(p: BProc, t: PNode) =
proc genBreakStmt(p: BProc, t: PNode) =
var idx = p.breakIdx
if t.sons[0].kind != nkEmpty:
if t.sons[0].kind != nkEmpty:
# named break?
assert(t.sons[0].kind == nkSym)
var sym = t.sons[0].sym
@@ -511,13 +511,13 @@ proc genBreakStmt(p: BProc, t: PNode) =
if idx < 0 or not p.blocks[idx].isLoop:
internalError(t.info, "no loop to break")
let label = assignLabel(p.blocks[idx])
blockLeaveActions(p,
blockLeaveActions(p,
p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
p.inExceptBlock - p.blocks[idx].nestedExceptStmts)
genLineDir(p, t)
lineF(p, cpsStmts, "goto $1;$n", [label])
proc getRaiseFrmt(p: BProc): string =
proc getRaiseFrmt(p: BProc): string =
if p.module.compileToCpp:
result = "throw NimException($1, $2);$n"
elif getCompilerProc("Exception") != nil:
@@ -532,7 +532,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
var finallyBlock = p.nestedTryStmts[p.nestedTryStmts.len - 1].lastSon
if finallyBlock.kind == nkFinally:
genSimpleBlock(p, finallyBlock.sons[0])
if t.sons[0].kind != nkEmpty:
if t.sons[0].kind != nkEmpty:
var a: TLoc
initLocExpr(p, t.sons[0], a)
var e = rdLoc(a)
@@ -547,23 +547,23 @@ proc genRaiseStmt(p: BProc, t: PNode) =
else:
linefmt(p, cpsStmts, "#reraiseException();$n")
proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
rangeFormat, eqFormat: TFormatStr, labl: TLabel) =
var
proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
rangeFormat, eqFormat: TFormatStr, labl: TLabel) =
var
x, y: TLoc
var length = sonsLen(b)
for i in countup(0, length - 2):
if b.sons[i].kind == nkRange:
for i in countup(0, length - 2):
if b.sons[i].kind == nkRange:
initLocExpr(p, b.sons[i].sons[0], x)
initLocExpr(p, b.sons[i].sons[1], y)
lineCg(p, cpsStmts, rangeFormat,
lineCg(p, cpsStmts, rangeFormat,
[rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
else:
else:
initLocExpr(p, b.sons[i], x)
lineCg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
labId, until: int): TLabel =
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
labId, until: int): TLabel =
var lend = getLabel(p)
for i in 1..until:
lineF(p, cpsStmts, "LA$1: ;$n", [toRope(labId + i)])
@@ -596,23 +596,23 @@ proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
else:
result = genCaseSecondPass(p, t, d, labId, until)
proc genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: TFormatStr) =
proc genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: TFormatStr) =
var a: TLoc
initLocExpr(p, t.sons[0], a)
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a)
fixLabel(p, lend)
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
branches: var openArray[PRope]) =
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
branches: var openArray[PRope]) =
var x: TLoc
var length = sonsLen(b)
for i in countup(0, length - 2):
for i in countup(0, length - 2):
assert(b.sons[i].kind != nkRange)
initLocExpr(p, b.sons[i], x)
assert(b.sons[i].kind in {nkStrLit..nkTripleStrLit})
var j = int(hashString(b.sons[i].strVal) and high(branches))
appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n",
appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n",
[rdLoc(e), rdLoc(x), labl])
proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
@@ -627,35 +627,35 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
var a: TLoc
initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
var labId = p.labels
for i in countup(1, sonsLen(t) - 1):
for i in countup(1, sonsLen(t) - 1):
inc(p.labels)
if t.sons[i].kind == nkOfBranch:
genCaseStringBranch(p, t.sons[i], a, con("LA", toRope(p.labels)),
if t.sons[i].kind == nkOfBranch:
genCaseStringBranch(p, t.sons[i], a, con("LA", toRope(p.labels)),
branches)
else:
else:
# else statement: nothing to do yet
# but we reserved a label, which we use later
discard
linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n",
linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n",
rdLoc(a), toRope(bitMask))
for j in countup(0, high(branches)):
if branches[j] != nil:
lineF(p, cpsStmts, "case $1: $n$2break;$n",
lineF(p, cpsStmts, "case $1: $n$2break;$n",
[intLiteral(j), branches[j]])
lineF(p, cpsStmts, "}$n") # else statement:
if t.sons[sonsLen(t)-1].kind != nkOfBranch:
lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)])
if t.sons[sonsLen(t)-1].kind != nkOfBranch:
lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)])
# third pass: generate statements
var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
fixLabel(p, lend)
else:
genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
proc branchHasTooBigRange(b: PNode): bool =
for i in countup(0, sonsLen(b)-2):
proc branchHasTooBigRange(b: PNode): bool =
for i in countup(0, sonsLen(b)-2):
# last son is block
if (b.sons[i].kind == nkRange) and
b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
return true
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
@@ -664,21 +664,21 @@ proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
var stmtBlock = lastSon(branch)
if stmtBlock.stmtsContainPragma(wLinearScanEnd):
result = i
elif hasSwitchRange notin CC[cCompiler].props:
if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
elif hasSwitchRange notin CC[cCompiler].props:
if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
result = i
proc genCaseRange(p: BProc, branch: PNode) =
var length = branch.len
for j in 0 .. length-2:
if branch[j].kind == nkRange:
if hasSwitchRange in CC[cCompiler].props:
for j in 0 .. length-2:
if branch[j].kind == nkRange:
if hasSwitchRange in CC[cCompiler].props:
lineF(p, cpsStmts, "case $1 ... $2:$n", [
genLiteral(p, branch[j][0]),
genLiteral(p, branch[j][0]),
genLiteral(p, branch[j][1])])
else:
else:
var v = copyNode(branch[j][0])
while v.intVal <= branch[j][1].intVal:
while v.intVal <= branch[j][1].intVal:
lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, v)])
inc(v.intVal)
else:
@@ -687,53 +687,53 @@ proc genCaseRange(p: BProc, branch: PNode) =
proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
# analyse 'case' statement:
var splitPoint = ifSwitchSplitPoint(p, n)
# generate if part (might be empty):
var a: TLoc
initLocExpr(p, n.sons[0], a)
var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
eqFormat = "if ($1 == $2) goto $3;$n",
eqFormat = "if ($1 == $2) goto $3;$n",
splitPoint, a) else: nil
# generate switch part (might be empty):
if splitPoint+1 < n.len:
lineF(p, cpsStmts, "switch ($1) {$n", [rdCharLoc(a)])
var hasDefault = false
for i in splitPoint+1 .. < n.len:
for i in splitPoint+1 .. < n.len:
var branch = n[i]
if branch.kind == nkOfBranch:
if branch.kind == nkOfBranch:
genCaseRange(p, branch)
else:
else:
# else part of case statement:
lineF(p, cpsStmts, "default:$n")
hasDefault = true
exprBlock(p, branch.lastSon, d)
lineF(p, cpsStmts, "break;$n")
if (hasAssume in CC[cCompiler].props) and not hasDefault:
if (hasAssume in CC[cCompiler].props) and not hasDefault:
lineF(p, cpsStmts, "default: __assume(0);$n")
lineF(p, cpsStmts, "}$n")
if lend != nil: fixLabel(p, lend)
proc genCase(p: BProc, t: PNode, d: var TLoc) =
proc genCase(p: BProc, t: PNode, d: var TLoc) =
genLineDir(p, t)
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
case skipTypes(t.sons[0].typ, abstractVarRange).kind
of tyString:
genStringCase(p, t, d)
of tyFloat..tyFloat128:
genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
of tyFloat..tyFloat128:
genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
"if ($1 == $2) goto $3;$n")
else:
genOrdinalCase(p, t, d)
proc hasGeneralExceptSection(t: PNode): bool =
proc hasGeneralExceptSection(t: PNode): bool =
var length = sonsLen(t)
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])
if blen == 1:
if blen == 1:
return true
inc(i)
result = false
@@ -798,7 +798,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
lineF(p, cpsStmts, "if ($1) ", [orExpr])
exprBlock(p, t.sons[i].sons[blen-1], d)
inc(i)
# reraise the exception if there was no catch all
# and none of the handlers matched
if not catchAllPresent:
@@ -811,15 +811,15 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
line(p, cpsStmts, ~"throw;$n")
endBlock(p)
lineF(p, cpsStmts, "}$n") # end of catch block
dec p.inExceptBlock
discard pop(p.nestedTryStmts)
if (i < length) and (t.sons[i].kind == nkFinally):
genSimpleBlock(p, t.sons[i].sons[0])
proc genTry(p: BProc, t: PNode, d: var TLoc) =
proc genTry(p: BProc, t: PNode, d: var TLoc) =
# code to generate:
#
# XXX: There should be a standard dispatch algorithm
@@ -841,7 +841,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
# clearException();
# }
# }
# {
# {
# /* finally: */
# printf('fin!\n');
# }
@@ -927,14 +927,14 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
res.add(rdLoc(a).ropeToStr)
else:
var r = sym.loc.r
if r == nil:
if r == nil:
# if no name has already been given,
# it doesn't matter much:
r = mangleName(sym)
sym.loc.r = r # but be consequent!
res.add(r.ropeToStr)
else: internalError(t.sons[i].info, "genAsmOrEmitStmt()")
if isAsmStmt and hasGnuAsm in CC[cCompiler].props:
for x in splitLines(res):
var j = 0
@@ -952,40 +952,43 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
res.add(tnl)
result = res.toRope
proc genAsmStmt(p: BProc, t: PNode) =
proc genAsmStmt(p: BProc, t: PNode) =
assert(t.kind == nkAsmStmt)
genLineDir(p, t)
var s = genAsmOrEmitStmt(p, t, isAsmStmt=true)
# see bug #2362, "top level asm statements" seem to be a mis-feature
# but even if we don't do this, the example in #2362 cannot possibly
# work:
if p.prc == nil:
# top level asm statement?
appf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s])
else:
lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s])
proc genEmit(p: BProc, t: PNode) =
proc genEmit(p: BProc, t: PNode) =
genLineDir(p, t)
var s = genAsmOrEmitStmt(p, t.sons[1])
if p.prc == nil:
if p.prc == nil:
# top level emit pragma?
app(p.module.s[cfsProcHeaders], s)
else:
line(p, cpsStmts, s)
var
var
breakPointId: int = 0
gBreakpoints: PRope # later the breakpoints are inserted into the main proc
proc genBreakPoint(p: BProc, t: PNode) =
proc genBreakPoint(p: BProc, t: PNode) =
var name: string
if optEndb in p.options:
if t.kind == nkExprColonExpr:
if t.kind == nkExprColonExpr:
assert(t.sons[1].kind in {nkStrLit..nkTripleStrLit})
name = normalize(t.sons[1].strVal)
else:
else:
inc(breakPointId)
name = "bp" & $breakPointId
genLineDir(p, t) # BUGFIX
appcg(p.module, gBreakpoints,
appcg(p.module, gBreakpoints,
"#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [
toRope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
makeCString(name)])
@@ -1006,14 +1009,14 @@ proc genPragma(p: BProc, n: PNode) =
of wEmit: genEmit(p, it)
of wBreakpoint: genBreakPoint(p, it)
of wWatchPoint: genWatchpoint(p, it)
of wInjectStmt:
of wInjectStmt:
var p = newProc(nil, p.module)
p.options = p.options - {optLineTrace, optStackTrace}
genStmts(p, it.sons[1])
p.module.injectStmt = p.s(cpsStmts)
else: discard
proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
if optFieldCheck in p.options:
var le = asgn.sons[0]
if le.kind == nkCheckedFieldExpr:
@@ -1021,23 +1024,23 @@ proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
result = sfDiscriminant in field.flags
elif le.kind == nkDotExpr:
var field = le.sons[1].sym
result = sfDiscriminant in field.flags
result = sfDiscriminant in field.flags
proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
field: PSym) =
proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
field: PSym) =
var t = skipTypes(objtype, abstractVar)
assert t.kind == tyObject
discard genTypeInfo(p.module, t)
var L = lengthOrd(field.typ)
if not containsOrIncl(p.module.declaredThings, field.id):
appcg(p.module, cfsVars, "extern $1",
appcg(p.module, cfsVars, "extern $1",
discriminatorTableDecl(p.module, t, field))
lineCg(p, cpsStmts,
"#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
intLiteral(L+1)])
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
var a, tmp: TLoc
var dotExpr = e.sons[0]
var d: PSym
@@ -1047,8 +1050,8 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
expr(p, e.sons[1], tmp)
genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, dotExpr.sons[1].sym)
genAssignment(p, a, tmp, {})
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
genLineDir(p, e)
if not fieldDiscriminantCheckNeeded(p, e):
var a: TLoc
@@ -1059,7 +1062,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
else:
asgnFieldDiscriminant(p, e)
proc genStmts(p: BProc, t: PNode) =
proc genStmts(p: BProc, t: PNode) =
var a: TLoc
expr(p, t, a)
internalAssert a.k in {locNone, locTemp, locLocalVar}

View File

@@ -9,7 +9,7 @@
## This module implements the C code generator.
import
import
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
options, intsets,
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
@@ -25,7 +25,7 @@ when options.hasTinyCBackend:
var
generatedHeader: BModule
proc addForwardedProc(m: BModule, prc: PSym) =
proc addForwardedProc(m: BModule, prc: PSym) =
m.forwardedProcs.add(prc)
inc(gForwardedProcsCounter)
@@ -33,7 +33,7 @@ proc getCgenModule(s: PSym): BModule =
result = if s.position >= 0 and s.position < gModules.len: gModules[s.position]
else: nil
proc findPendingModule(m: BModule, s: PSym): BModule =
proc findPendingModule(m: BModule, s: PSym): BModule =
var ms = getModule(s)
result = gModules[ms.position]
@@ -41,21 +41,21 @@ proc emitLazily(s: PSym): bool {.inline.} =
result = optDeadCodeElim in gGlobalOptions or
sfDeadCodeElim in getModule(s).flags
proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
result.k = k
result.s = s
result.t = typ
result.r = nil
result.flags = {}
proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
# fills the loc if it is not already initialized
if a.k == locNone:
if a.k == locNone:
a.k = k
a.t = typ
a.s = s
if a.r == nil: a.r = r
proc isSimpleConst(typ: PType): bool =
let t = skipTypes(typ, abstractVar)
result = t.kind notin
@@ -67,43 +67,43 @@ proc useStringh(m: BModule) =
m.includesStringh = true
discard lists.includeStr(m.headerFiles, "<string.h>")
proc useHeader(m: BModule, sym: PSym) =
if lfHeader in sym.loc.flags:
proc useHeader(m: BModule, sym: PSym) =
if lfHeader in sym.loc.flags:
assert(sym.annex != nil)
discard lists.includeStr(m.headerFiles, getStr(sym.annex.path))
proc cgsym(m: BModule, name: string): PRope
proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
var i = 0
var length = len(frmt)
result = nil
var num = 0
while i < length:
if frmt[i] == '$':
while i < length:
if frmt[i] == '$':
inc(i) # skip '$'
case frmt[i]
of '$':
of '$':
app(result, "$")
inc(i)
of '#':
of '#':
inc(i)
app(result, args[num])
inc(num)
of '0'..'9':
of '0'..'9':
var j = 0
while true:
while true:
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
if i >= length or not (frmt[i] in {'0'..'9'}): break
if i >= length or not (frmt[i] in {'0'..'9'}): break
num = j
if j > high(args) + 1:
if j > high(args) + 1:
internalError("ropes: invalid format string $" & $j)
app(result, args[j-1])
of 'n':
if optLineDir notin gOptions: app(result, rnl)
inc(i)
of 'N':
of 'N':
app(result, rnl)
inc(i)
else: internalError("ropes: invalid format string $" & frmt[i])
@@ -117,37 +117,37 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
elif frmt[i] == '#' and frmt[i+1] == '$':
inc(i, 2)
var j = 0
while frmt[i] in Digits:
while frmt[i] in Digits:
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
app(result, cgsym(m, args[j-1].ropeToStr))
var start = i
while i < length:
while i < length:
if frmt[i] != '$' and frmt[i] != '#': inc(i)
else: break
if i - 1 >= start:
else: break
if i - 1 >= start:
app(result, substr(frmt, start, i - 1))
template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
ropecg(m, fmt, args)
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
args: varargs[PRope]) =
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
args: varargs[PRope]) =
app(c, ropecg(m, frmt, args))
proc appcg(m: BModule, s: TCFileSection, frmt: TFormatStr,
args: varargs[PRope]) =
proc appcg(m: BModule, s: TCFileSection, frmt: TFormatStr,
args: varargs[PRope]) =
app(m.s[s], ropecg(m, frmt, args))
proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr,
args: varargs[PRope]) =
proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr,
args: varargs[PRope]) =
app(p.s(s), ropecg(p.module, frmt, args))
var indent = "\t".toRope
proc indentLine(p: BProc, r: PRope): PRope =
result = r
for i in countup(0, p.blocks.len-1): prepend(result, indent)
proc line(p: BProc, s: TCProcSection, r: PRope) =
app(p.s(s), indentLine(p, r))
@@ -180,7 +180,7 @@ proc genCLineDir(r: var PRope, filename: string, line: int) =
appf(r, "$N#line $2 $1$N",
[toRope(makeSingleLineCString(filename)), toRope(line)])
proc genCLineDir(r: var PRope, info: TLineInfo) =
proc genCLineDir(r: var PRope, info: TLineInfo) =
genCLineDir(r, info.toFullPath, info.safeLineNm)
proc genLineDir(p: BProc, t: PNode) =
@@ -261,7 +261,9 @@ proc isComplexValueType(t: PType): bool {.inline.} =
proc resetLoc(p: BProc, loc: var TLoc) =
let containsGcRef = containsGarbageCollectedRef(loc.t)
if not isComplexValueType(skipTypes(loc.t, abstractVarRange)):
let typ = skipTypes(loc.t, abstractVarRange)
if isImportedCppType(typ): return
if not isComplexValueType(typ):
if containsGcRef:
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.t, OnStack)
@@ -282,35 +284,37 @@ proc resetLoc(p: BProc, loc: var TLoc) =
useStringh(p.module)
linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
addrLoc(loc), rdLoc(loc))
# XXX: We can be extra clever here and call memset only
# 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)
proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
if not isComplexValueType(skipTypes(loc.t, abstractRange)):
let typ = skipTypes(loc.t, abstractRange)
if not isComplexValueType(typ):
linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
else:
if not isTemp or containsGarbageCollectedRef(loc.t):
# don't use memset for temporary values for performance if we can
# avoid it:
useStringh(p.module)
linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
addrLoc(loc), rdLoc(loc))
if not isImportedCppType(typ):
useStringh(p.module)
linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
addrLoc(loc), rdLoc(loc))
genObjectInit(p, cpsStmts, loc.t, loc, true)
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
if sfNoInit notin v.flags:
# we know it is a local variable and thus on the stack!
# If ``not immediateAsgn`` it is not initialized in a binding like
# ``var v = X`` and thus we need to init it.
# ``var v = X`` and thus we need to init it.
# If ``v`` contains a GC-ref we may pass it to ``unsureAsgnRef`` somehow
# which requires initialization. However this can really only happen if
# ``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.
if not immediateAsgn:
constructLoc(p, v.loc)
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
inc(p.labels)
result.r = con("LOC", toRope(p.labels))
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
@@ -353,10 +357,10 @@ proc deinitGCFrame(p: BProc): PRope =
if p.gcFrameId > 0:
result = ropecg(p.module,
"if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n")
proc allocParam(p: BProc, s: PSym) =
proc allocParam(p: BProc, s: PSym) =
assert(s.kind == skParam)
if lfParamCopy notin s.loc.flags:
if lfParamCopy notin s.loc.flags:
inc(p.labels)
var tmp = con("%LOC", toRope(p.labels))
incl(s.loc.flags, lfParamCopy)
@@ -365,8 +369,8 @@ proc allocParam(p: BProc, s: PSym) =
[tmp, s.loc.r, getTypeDesc(p.module, s.loc.t)])
s.loc.r = tmp
proc localDebugInfo(p: BProc, s: PSym) =
if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
proc localDebugInfo(p: BProc, s: PSym) =
if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
# XXX work around a bug: No type information for open arrays possible:
if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
var a = con("&", s.loc.r)
@@ -379,7 +383,7 @@ proc localDebugInfo(p: BProc, s: PSym) =
inc p.blocks[p.blocks.len-1].frameLen
proc localVarDecl(p: BProc; s: PSym): PRope =
if s.loc.k == locNone:
if s.loc.k == locNone:
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
result = getTypeDesc(p.module, s.loc.t)
@@ -406,22 +410,22 @@ include ccgthreadvars
proc varInDynamicLib(m: BModule, sym: PSym)
proc mangleDynLibProc(sym: PSym): PRope
proc assignGlobalVar(p: BProc, s: PSym) =
if s.loc.k == locNone:
proc assignGlobalVar(p: BProc, s: PSym) =
if s.loc.k == locNone:
fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap)
if lfDynamicLib in s.loc.flags:
var q = findPendingModule(p.module, s)
if q != nil and not containsOrIncl(q.declaredThings, s.id):
if q != nil and not containsOrIncl(q.declaredThings, s.id):
varInDynamicLib(q, s)
else:
s.loc.r = mangleDynLibProc(s)
return
useHeader(p.module, s)
if lfNoDecl in s.loc.flags: return
if sfThread in s.flags:
if sfThread in s.flags:
declareThreadVar(p.module, s, sfImportc in s.flags)
else:
else:
var decl: PRope = nil
var td = getTypeDesc(p.module, s.loc.t)
if s.constraint.isNil:
@@ -437,25 +441,25 @@ proc assignGlobalVar(p: BProc, s: PSym) =
# fixes tests/run/tzeroarray:
resetLoc(p, s.loc)
if p.module.module.options * {optStackTrace, optEndb} ==
{optStackTrace, optEndb}:
appcg(p.module, p.module.s[cfsDebugInit],
"#dbgRegisterGlobal($1, &$2, $3);$n",
[makeCString(normalize(s.owner.name.s & '.' & s.name.s)),
{optStackTrace, optEndb}:
appcg(p.module, p.module.s[cfsDebugInit],
"#dbgRegisterGlobal($1, &$2, $3);$n",
[makeCString(normalize(s.owner.name.s & '.' & s.name.s)),
s.loc.r, genTypeInfo(p.module, s.typ)])
proc assignParam(p: BProc, s: PSym) =
proc assignParam(p: BProc, s: PSym) =
assert(s.loc.r != nil)
localDebugInfo(p, s)
proc fillProcLoc(sym: PSym) =
if sym.loc.k == locNone:
proc fillProcLoc(sym: PSym) =
if sym.loc.k == locNone:
fillLoc(sym.loc, locProc, sym.typ, mangleName(sym), OnStack)
proc getLabel(p: BProc): TLabel =
proc getLabel(p: BProc): TLabel =
inc(p.labels)
result = con("LA", toRope(p.labels))
proc fixLabel(p: BProc, labl: TLabel) =
proc fixLabel(p: BProc, labl: TLabel) =
lineF(p, cpsStmts, "$1: ;$n", [labl])
proc genVarPrototype(m: BModule, sym: PSym)
@@ -487,12 +491,12 @@ include ccgcalls, "ccgstmts.nim", "ccgexprs.nim"
proc isGetProcAddr(lib: PLib): bool =
let n = lib.path
result = n.kind in nkCallKinds and n.typ != nil and
result = n.kind in nkCallKinds and n.typ != nil and
n.typ.kind in {tyPointer, tyProc}
proc loadDynamicLib(m: BModule, lib: PLib) =
proc loadDynamicLib(m: BModule, lib: PLib) =
assert(lib != nil)
if not lib.generated:
if not lib.generated:
lib.generated = true
var tmp = getGlobalTempName()
assert(lib.name == nil)
@@ -504,14 +508,14 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
if gVerbosity >= 2:
msgWriteln("Dependency: " & lib.path.strVal)
var loadlib: PRope = nil
for i in countup(0, high(s)):
for i in countup(0, high(s)):
inc(m.labels)
if i > 0: app(loadlib, "||")
appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n",
appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n",
[tmp, getStrLit(m, s[i])])
appcg(m, m.s[cfsDynLibInit],
"if (!($1)) #nimLoadLibraryError((#NimStringDesc*) &$2);$n",
[loadlib, getStrLit(m, lib.path.strVal)])
appcg(m, m.s[cfsDynLibInit],
"if (!($1)) #nimLoadLibraryError((#NimStringDesc*) &$2);$n",
[loadlib, getStrLit(m, lib.path.strVal)])
else:
var p = newProc(nil, m)
p.options = p.options - {optStackTrace, optEndb}
@@ -520,20 +524,20 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
app(m.s[cfsVars], p.s(cpsLocals))
app(m.s[cfsDynLibInit], p.s(cpsInit))
app(m.s[cfsDynLibInit], p.s(cpsStmts))
appcg(m, m.s[cfsDynLibInit],
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
appcg(m, m.s[cfsDynLibInit],
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
[tmp, rdLoc(dest)])
if lib.name == nil: internalError("loadDynamicLib")
proc mangleDynLibProc(sym: PSym): PRope =
if sfCompilerProc in sym.flags:
if sfCompilerProc in sym.flags:
# NOTE: sym.loc.r is the external name!
result = toRope(sym.name.s)
else:
result = ropef("Dl_$1", [toRope(sym.id)])
proc symInDynamicLib(m: BModule, sym: PSym) =
proc symInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
let isCall = isGetProcAddr(lib)
var extname = sym.loc.r
@@ -565,13 +569,13 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
else:
internalError(sym.info, "wrong index: " & idx)
else:
appcg(m, m.s[cfsDynLibInit],
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ),
appcg(m, m.s[cfsDynLibInit],
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ),
lib.name, makeCString(ropeToStr(extname))])
appf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
proc varInDynamicLib(m: BModule, sym: PSym) =
proc varInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
var extname = sym.loc.r
loadDynamicLib(m, lib)
@@ -579,9 +583,9 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
var tmp = mangleDynLibProc(sym)
sym.loc.r = tmp # from now on we only need the internal name
inc(m.labels, 2)
appcg(m, m.s[cfsDynLibInit],
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ),
appcg(m, m.s[cfsDynLibInit],
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ),
lib.name, makeCString(ropeToStr(extname))])
appf(m.s[cfsVars], "$2* $1;$n",
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
@@ -590,9 +594,9 @@ proc symInDynamicLibPartial(m: BModule, sym: PSym) =
sym.loc.r = mangleDynLibProc(sym)
sym.typ.sym = nil # generate a new name
proc cgsym(m: BModule, name: string): PRope =
proc cgsym(m: BModule, name: string): PRope =
var sym = magicsys.getCompilerProc(name)
if sym != nil:
if sym != nil:
case sym.kind
of skProc, skMethod, skConverter, skIterators: genProc(m, sym)
of skVar, skResult, skLet: genVarPrototype(m, sym)
@@ -604,18 +608,18 @@ proc cgsym(m: BModule, name: string): PRope =
# we're picky here for the system module too:
rawMessage(errSystemNeeds, name)
result = sym.loc.r
proc generateHeaders(m: BModule) =
app(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl)
var it = PStrEntry(m.headerFiles.head)
while it != nil:
if it.data[0] notin {'\"', '<'}:
if it.data[0] notin {'\"', '<'}:
appf(m.s[cfsHeaders], "$N#include \"$1\"$N", [toRope(it.data)])
else:
appf(m.s[cfsHeaders], "$N#include $1$N", [toRope(it.data)])
it = PStrEntry(it.next)
proc retIsNotVoid(s: PSym): bool =
proc retIsNotVoid(s: PSym): bool =
result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
proc initFrame(p: BProc, procname, filename: PRope): PRope =
@@ -663,11 +667,11 @@ proc genProcAux(m: BModule, prc: PSym) =
else:
fillResult(res)
assignParam(p, res)
if skipTypes(res.typ, abstractInst).kind == tyArray:
if skipTypes(res.typ, abstractInst).kind == tyArray:
incl(res.loc.flags, lfIndirect)
res.loc.s = OnUnknown
for i in countup(1, sonsLen(prc.typ.n) - 1):
for i in countup(1, sonsLen(prc.typ.n) - 1):
var param = prc.typ.n.sons[i].sym
if param.typ.isCompileTimeOnly: continue
assignParam(p, param)
@@ -682,11 +686,11 @@ proc genProcAux(m: BModule, prc: PSym) =
else:
generatedProc = rfmt(nil, "$N$1 {$N", header)
app(generatedProc, initGCFrame(p))
if optStackTrace in prc.options:
if optStackTrace in prc.options:
app(generatedProc, p.s(cpsLocals))
var procname = makeCString(prc.name.s)
app(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
else:
else:
app(generatedProc, p.s(cpsLocals))
if optProfiler in prc.options:
# invoke at proc entry for recursion:
@@ -706,12 +710,12 @@ proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} =
sfCompileToCpp notin sym.getModule().flags and
gCmd != cmdCompileToCpp
proc genProcPrototype(m: BModule, sym: PSym) =
proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym)
if lfNoDecl in sym.loc.flags: return
if lfNoDecl in sym.loc.flags: return
if lfDynamicLib in sym.loc.flags:
if getModule(sym).id != m.module.id and
not containsOrIncl(m.declaredThings, sym.id):
not containsOrIncl(m.declaredThings, sym.id):
app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
elif not containsOrIncl(m.declaredProtos, sym.id):
@@ -722,13 +726,13 @@ proc genProcPrototype(m: BModule, sym: PSym) =
header.app(" __attribute__((naked))")
app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
proc genProcNoForward(m: BModule, prc: PSym) =
proc genProcNoForward(m: BModule, prc: PSym) =
fillProcLoc(prc)
useHeader(m, prc)
if lfImportCompilerProc in prc.loc.flags:
# dependency to a compilerproc:
discard cgsym(m, prc.name.s)
return
return
genProcPrototype(m, prc)
if lfNoDecl in prc.loc.flags: discard
elif prc.typ.callConv == ccInline:
@@ -738,13 +742,13 @@ proc genProcNoForward(m: BModule, prc: PSym) =
if not containsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
elif lfDynamicLib in prc.loc.flags:
var q = findPendingModule(m, prc)
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
symInDynamicLib(q, prc)
else:
symInDynamicLibPartial(m, prc)
elif sfImportc notin prc.flags:
var q = findPendingModule(m, prc)
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
genProcAux(q, prc)
proc requestConstImpl(p: BProc, sym: PSym) =
@@ -770,7 +774,7 @@ proc requestConstImpl(p: BProc, sym: PSym) =
proc isActivated(prc: PSym): bool = prc.typ != nil
proc genProc(m: BModule, prc: PSym) =
proc genProc(m: BModule, prc: PSym) =
if sfBorrow in prc.flags or not isActivated(prc): return
fillProcLoc(prc)
if sfForward in prc.flags: addForwardedProc(m, prc)
@@ -780,19 +784,19 @@ proc genProc(m: BModule, prc: PSym) =
generatedHeader != nil and lfNoDecl notin prc.loc.flags:
genProcPrototype(generatedHeader, prc)
if prc.typ.callConv == ccInline:
if not containsOrIncl(generatedHeader.declaredThings, prc.id):
if not containsOrIncl(generatedHeader.declaredThings, prc.id):
genProcAux(generatedHeader, prc)
proc genVarPrototypeAux(m: BModule, sym: PSym) =
proc genVarPrototypeAux(m: BModule, sym: PSym) =
assert(sfGlobal in sym.flags)
useHeader(m, sym)
fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap)
if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id):
return
if sym.owner.id != m.module.id:
if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id):
return
if sym.owner.id != m.module.id:
# else we already have the symbol generated!
assert(sym.loc.r != nil)
if sfThread in sym.flags:
if sfThread in sym.flags:
declareThreadVar(m, sym, true)
else:
app(m.s[cfsVars], "extern ")
@@ -838,7 +842,7 @@ proc genFilenames(m: BModule): PRope =
result.appf("dbgRegisterFilename($1);$N", fileInfos[i].projPath.makeCString)
proc genMainProc(m: BModule) =
const
const
# The use of a volatile function pointer to call Pre/NimMainInner
# prevents inlining of the NimMainInner function and dependent
# functions, which might otherwise merge their stack frames.
@@ -859,7 +863,7 @@ proc genMainProc(m: BModule) =
MainProcs =
"\tNimMain();$N"
MainProcsWithResult =
MainProcs & "\treturn nim_program_result;$N"
@@ -880,7 +884,7 @@ proc genMainProc(m: BModule) =
"char** cmdLine;$N" &
"char** gEnv;$N" &
NimMainBody
PosixCMain =
"int main(int argc, char** args, char** env) {$N" &
"\tcmdLine = args;$N" &
@@ -888,20 +892,20 @@ proc genMainProc(m: BModule) =
"\tgEnv = env;$N" &
MainProcsWithResult &
"}$N$N"
StandaloneCMain =
"int main(void) {$N" &
MainProcs &
"\treturn 0;$N" &
"}$N$N"
WinNimMain = NimMainBody
WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $N" &
" HINSTANCE hPrevInstance, $N" &
" LPSTR lpCmdLine, int nCmdShow) {$N" &
MainProcsWithResult & "}$N$N"
WinNimDllMain = "N_LIB_EXPORT " & NimMainBody
WinCDllMain =
@@ -911,7 +915,7 @@ proc genMainProc(m: BModule) =
"\treturn 1;$N}$N$N"
PosixNimDllMain = WinNimDllMain
PosixCDllMain =
"void NIM_POSIX_INIT NimMainInit(void) {$N" &
MainProcs &
@@ -919,11 +923,11 @@ proc genMainProc(m: BModule) =
var nimMain, otherMain: TFormatStr
if platform.targetOS == osWindows and
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
if optGenGuiApp in gGlobalOptions:
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
if optGenGuiApp in gGlobalOptions:
nimMain = WinNimMain
otherMain = WinCMain
else:
else:
nimMain = WinNimDllMain
otherMain = WinCDllMain
discard lists.includeStr(m.headerFiles, "<windows.h>")
@@ -939,7 +943,7 @@ proc genMainProc(m: BModule) =
if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
if optEndb in gOptions:
gBreakpoints.app(m.genFilenames)
let initStackBottomCall =
if platform.targetOS == osStandalone: "".toRope
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
@@ -964,11 +968,11 @@ proc getSomeInitName(m: PSym, suffix: string): PRope =
result.app "_"
result.app m.name.s
result.app suffix
proc getInitName(m: PSym): PRope = getSomeInitName(m, "Init")
proc getDatInitName(m: PSym): PRope = getSomeInitName(m, "DatInit")
proc registerModuleToMain(m: PSym) =
proc registerModuleToMain(m: PSym) =
var
init = m.getInitName
datInit = m.getDatInitName
@@ -981,19 +985,19 @@ proc registerModuleToMain(m: PSym) =
app(mainModInit, initCall)
else:
app(otherModsInit, initCall)
proc genInitCode(m: BModule) =
proc genInitCode(m: BModule) =
var initname = getInitName(m.module)
var prc = ropef("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", [initname])
if m.typeNodes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
if m.typeNodes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
[m.typeNodesName, toRope(m.typeNodes)])
if m.nimTypes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n",
if m.nimTypes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n",
[m.nimTypesName, toRope(m.nimTypes)])
app(prc, initGCFrame(m.initProc))
app(prc, genSectionStart(cpsLocals))
app(prc, m.preInitProc.s(cpsLocals))
app(prc, m.initProc.s(cpsLocals))
@@ -1009,7 +1013,7 @@ proc genInitCode(m: BModule) =
app(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
else:
app(prc, ~"\tTFrame F; F.len = 0;$N")
app(prc, genSectionStart(cpsInit))
app(prc, m.preInitProc.s(cpsInit))
app(prc, m.initProc.s(cpsInit))
@@ -1033,27 +1037,27 @@ proc genInitCode(m: BModule) =
app(prc, genSectionStart(i))
app(prc, m.s[i])
app(prc, genSectionEnd(i))
appf(prc, "}$N$N")
# we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
# that would lead to a *nesting* of merge sections which the merger does
# not support. So we add it to another special section: ``cfsInitProc``
app(m.s[cfsInitProc], prc)
for i, el in pairs(m.extensionLoaders):
if el != nil:
let ex = ropef("N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N",
(i.ord - '0'.ord).toRope, el)
app(m.s[cfsInitProc], ex)
proc genModule(m: BModule, cfile: string): PRope =
proc genModule(m: BModule, cfile: string): PRope =
result = getFileHeader(cfile)
result.app(genMergeInfo(m))
generateHeaders(m)
generateThreadLocalStorage(m)
for i in countup(cfsHeaders, cfsProcs):
for i in countup(cfsHeaders, cfsProcs):
app(result, genSectionStart(i))
app(result, m.s[i])
app(result, genSectionEnd(i))
@@ -1069,7 +1073,7 @@ proc newPostInitProc(m: BModule): BProc =
# little hack so that unique temporaries are generated:
result.labels = 200_000
proc initProcOptions(m: BModule): TOptions =
proc initProcOptions(m: BModule): TOptions =
if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions
proc rawNewModule(module: PSym, filename: string): BModule =
@@ -1124,11 +1128,11 @@ proc resetModule*(m: BModule) =
m.typeNodes = 0
m.nimTypes = 0
nullify m.extensionLoaders
# indicate that this is now cached module
# the cache will be invalidated by nullifying gModules
m.fromCache = true
# we keep only the "merge info" information for the module
# and the properties that can't change:
# m.filename
@@ -1155,11 +1159,11 @@ proc newModule(module: PSym): BModule =
growCache gModules, module.position
gModules[module.position] = result
if (optDeadCodeElim in gGlobalOptions):
if (sfDeadCodeElim in module.flags):
if (optDeadCodeElim in gGlobalOptions):
if (sfDeadCodeElim in module.flags):
internalError("added pending module twice: " & module.filename)
proc myOpen(module: PSym): PPassContext =
proc myOpen(module: PSym): PPassContext =
result = newModule(module)
if optGenIndex in gGlobalOptions and generatedHeader == nil:
let f = if headerFile.len > 0: headerFile else: gProjectFull
@@ -1175,12 +1179,12 @@ proc writeHeader(m: BModule) =
generateHeaders(m)
generateThreadLocalStorage(m)
for i in countup(cfsHeaders, cfsProcs):
for i in countup(cfsHeaders, cfsProcs):
app(result, genSectionStart(i))
app(result, m.s[i])
app(result, genSectionEnd(i))
app(result, m.s[cfsInitProc])
if optGenDynLib in gGlobalOptions:
result.app("N_LIB_IMPORT ")
result.appf("N_CDECL(void, NimMain)(void);$n")
@@ -1200,20 +1204,20 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
readMergeInfo(getCFile(m), m)
result = m
proc myProcess(b: PPassContext, n: PNode): PNode =
proc myProcess(b: PPassContext, n: PNode): PNode =
result = n
if b == nil or passes.skipCodegen(n): return
var m = BModule(b)
m.initProc.options = initProcOptions(m)
genStmts(m.initProc, n)
proc finishModule(m: BModule) =
proc finishModule(m: BModule) =
var i = 0
while i <= high(m.forwardedProcs):
while i <= high(m.forwardedProcs):
# Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
# a ``for`` loop here
var prc = m.forwardedProcs[i]
if sfForward in prc.flags:
if sfForward in prc.flags:
internalError(prc.info, "still forwarded: " & prc.name.s)
genProcNoForward(m, prc)
inc(i)
@@ -1221,13 +1225,13 @@ proc finishModule(m: BModule) =
dec(gForwardedProcsCounter, i)
setLen(m.forwardedProcs, 0)
proc shouldRecompile(code: PRope, cfile: string): bool =
proc shouldRecompile(code: PRope, cfile: string): bool =
result = true
if optForceFullMake notin gGlobalOptions:
var objFile = toObjFile(cfile)
if writeRopeIfNotEqual(code, cfile): return
if writeRopeIfNotEqual(code, cfile): return
if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false
else:
else:
writeRope(code, cfile)
# We need 2 different logics here: pending modules (including
@@ -1240,15 +1244,15 @@ proc writeModule(m: BModule, pending: bool) =
# generate code for the init statements of the module:
var cfile = getCFile(m)
var cfilenoext = changeFileExt(cfile, "")
if not m.fromCache or optForceFullMake in gGlobalOptions:
genInitCode(m)
finishTypeDescriptions(m)
if sfMainModule in m.module.flags:
if sfMainModule in m.module.flags:
# generate main file:
app(m.s[cfsProcHeaders], mainModProcs)
generateThreadVarsSize(m)
var code = genModule(m, cfile)
when hasTinyCBackend:
if gCmd == cmdRun:
@@ -1269,13 +1273,13 @@ proc writeModule(m: BModule, pending: bool) =
# ``system.c`` but then compilation fails due to an error. This means
# that ``system.o`` is missing, so we need to call the C compiler for it:
addFileToCompile(cfile)
addFileToLink(cfilenoext)
proc updateCachedModule(m: BModule) =
let cfile = getCFile(m)
let cfilenoext = changeFileExt(cfile, "")
if mergeRequired(m) and sfMainModule notin m.module.flags:
mergeFiles(cfile, m)
genInitCode(m)
@@ -1286,17 +1290,17 @@ proc updateCachedModule(m: BModule) =
addFileToLink(cfilenoext)
proc myClose(b: PPassContext, n: PNode): PNode =
proc myClose(b: PPassContext, n: PNode): PNode =
result = n
if b == nil or passes.skipCodegen(n): return
if b == nil or passes.skipCodegen(n): return
var m = BModule(b)
if n != nil:
if n != nil:
m.initProc.options = initProcOptions(m)
genStmts(m.initProc, n)
# cached modules need to registered too:
# cached modules need to registered too:
registerModuleToMain(m.module)
if sfMainModule in m.module.flags:
if sfMainModule in m.module.flags:
m.objHasKidsValid = true
var disp = generateMethodDispatchers()
for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)

View File

@@ -9,8 +9,8 @@
# This module implements lookup helpers.
import
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
import
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
renderer, wordrecg, idgen, nimfix.prettybase
proc ensureNoMissingOrUnusedSymbols(scope: PScope)
@@ -87,14 +87,14 @@ proc searchInScopes*(c: PContext, s: PIdent): PSym =
if result != nil: return
result = nil
proc debugScopes*(c: PContext) {.deprecated.} =
proc debugScopes*(c: PContext; limit=0) {.deprecated.} =
var i = 0
for scope in walkScopes(c.currentScope):
echo "scope ", i
for h in 0 .. high(scope.symbols.data):
if scope.symbols.data[h] != nil:
echo scope.symbols.data[h].name.s
if i == 2: break
if i == limit: break
inc i
proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
@@ -108,7 +108,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
var m = n
# ensure that 'considerQuotedIdent' can't fail:
if m.kind == nkDotExpr: m = m.sons[1]
let ident = if m.kind in {nkIdent, nkSym, nkAccQuoted}:
let ident = if m.kind in {nkIdent, nkSym, nkAccQuoted}:
considerQuotedIdent(m)
else:
getIdent("err:" & renderTree(m))
@@ -119,11 +119,11 @@ proc errorSym*(c: PContext, n: PNode): PSym =
if gCmd != cmdInteractive and c.inCompilesContext == 0:
c.importTable.addSym(result)
type
TOverloadIterMode* = enum
type
TOverloadIterMode* = enum
oimDone, oimNoQualifier, oimSelfModule, oimOtherModule, oimSymChoice,
oimSymChoiceLocalLookup
TOverloadIter*{.final.} = object
TOverloadIter*{.final.} = object
it*: TIdentIter
m*: PSym
mode*: TOverloadIterMode
@@ -131,7 +131,7 @@ type
scope*: PScope
inSymChoice: IntSet
proc getSymRepr*(s: PSym): string =
proc getSymRepr*(s: PSym): string =
case s.kind
of skProc, skMethod, skConverter, skIterators: result = getProcHeader(s)
else: result = s.name.s
@@ -148,7 +148,7 @@ proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
if missingImpls == 0:
localError(s.info, errImplOfXexpected, getSymRepr(s))
inc missingImpls
elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options:
elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options:
# BUGFIX: check options in s!
if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
# XXX: implicit type params are currently skTypes
@@ -156,11 +156,11 @@ proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
if s.typ != nil and tfImplicitTypeParam notin s.typ.flags:
message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
s = nextIter(it, scope.symbols)
proc wrongRedefinition*(info: TLineInfo, s: string) =
if gCmd != cmdInteractive:
localError(info, errAttemptToRedefine, s)
proc addDecl*(c: PContext, sym: PSym) =
if not c.currentScope.addUniqueSym(sym):
wrongRedefinition(sym.info, sym.name.s)
@@ -172,7 +172,7 @@ proc addDeclAt*(scope: PScope, sym: PSym) =
if not scope.addUniqueSym(sym):
wrongRedefinition(sym.info, sym.name.s)
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
if sfExported in sym.flags:
# add to interface:
if c.module != nil: strTableAdd(c.module.tab, sym)
@@ -183,16 +183,16 @@ proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
addInterfaceDeclAux(c, sym)
proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
if fn.kind notin OverloadableSyms:
if fn.kind notin OverloadableSyms:
internalError(fn.info, "addOverloadableSymAt")
return
let check = strTableGet(scope.symbols, fn.name)
if check != nil and check.kind notin OverloadableSyms:
if check != nil and check.kind notin OverloadableSyms:
wrongRedefinition(fn.info, fn.name.s)
else:
scope.addSym(fn)
proc addInterfaceDecl*(c: PContext, sym: PSym) =
proc addInterfaceDecl*(c: PContext, sym: PSym) =
# it adds the symbol to the interface if appropriate
addDecl(c, sym)
addInterfaceDeclAux(c, sym)
@@ -221,7 +221,7 @@ when defined(nimfix):
else:
template fixSpelling(n: PNode; ident: PIdent; op: expr) = discard
proc lookUp*(c: PContext, n: PNode): PSym =
proc lookUp*(c: PContext, n: PNode): PSym =
# Looks up a symbol. Generates an error in case of nil.
case n.kind
of nkIdent:
@@ -242,12 +242,12 @@ proc lookUp*(c: PContext, n: PNode): PSym =
else:
internalError(n.info, "lookUp")
return
if contains(c.ambiguousSymbols, result.id):
if contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, result.name.s)
if result.kind == skStub: loadStub(result)
type
TLookupFlag* = enum
type
TLookupFlag* = enum
checkAmbiguity, checkUndeclared
proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
@@ -294,7 +294,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
else:
result = nil
if result != nil and result.kind == skStub: loadStub(result)
proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
case n.kind
of nkIdent, nkAccQuoted:
@@ -311,17 +311,17 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
of nkSym:
result = n.sym
o.mode = oimDone
of nkDotExpr:
of nkDotExpr:
o.mode = oimOtherModule
o.m = qualifiedLookUp(c, n.sons[0])
if o.m != nil and o.m.kind == skModule:
var ident: PIdent = nil
if n.sons[1].kind == nkIdent:
if n.sons[1].kind == nkIdent:
ident = n.sons[1].ident
elif n.sons[1].kind == nkAccQuoted:
ident = considerQuotedIdent(n.sons[1])
if ident != nil:
if o.m == c.module:
if ident != nil:
if o.m == c.module:
# a module may access its private members:
result = initIdentIter(o.it, c.topLevelScope.symbols,
ident).skipAlias(n)
@@ -329,7 +329,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
else:
result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n)
else:
localError(n.sons[1].info, errIdentifierExpected,
localError(n.sons[1].info, errIdentifierExpected,
renderTree(n.sons[1]))
result = errorSym(c, n.sons[1])
of nkClosedSymChoice, nkOpenSymChoice:
@@ -347,12 +347,12 @@ proc lastOverloadScope*(o: TOverloadIter): int =
of oimSelfModule: result = 1
of oimOtherModule: result = 0
else: result = -1
proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
case o.mode
of oimDone:
of oimDone:
result = nil
of oimNoQualifier:
of oimNoQualifier:
if o.scope != nil:
result = nextIdentIter(o.it, o.scope.symbols).skipAlias(n)
while result == nil:
@@ -360,13 +360,13 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
if o.scope == nil: break
result = initIdentIter(o.it, o.scope.symbols, o.it.name).skipAlias(n)
# BUGFIX: o.it.name <-> n.ident
else:
else:
result = nil
of oimSelfModule:
of oimSelfModule:
result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n)
of oimOtherModule:
of oimOtherModule:
result = nextIdentIter(o.it, o.m.tab).skipAlias(n)
of oimSymChoice:
of oimSymChoice:
if o.symChoiceIndex < sonsLen(n):
result = n.sons[o.symChoiceIndex].sym
incl(o.inSymChoice, result.id)
@@ -389,7 +389,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
if o.scope == nil: break
result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
if result != nil and result.kind == skStub: loadStub(result)
proc pickSym*(c: PContext, n: PNode; kind: TSymKind;

View File

@@ -9,19 +9,19 @@
# This module implements semantic checking for pragmas
import
os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
import
os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
wordrecg, ropes, options, strutils, lists, extccomp, math, magicsys, trees,
rodread, types, lookups
const
const
FirstCallConv* = wNimcall
LastCallConv* = wNoconv
const
procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wMagic, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wMagic, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
@@ -33,7 +33,7 @@ const
macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern,
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator}
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
wTags, wLocks, wGcSafe}
@@ -46,18 +46,18 @@ const
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
wInjectStmt, wDeprecated, wExperimental}
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
wRaises, wLocks, wTags, wGcSafe}
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
wBorrow, wGcSafe}
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
wImportCpp, wImportObjC, wError, wGuard}
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
wGensym, wInject, wCodegenDecl, wGuard}
@@ -74,18 +74,18 @@ proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
proc invalidPragma(n: PNode) =
localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
proc pragmaAsm*(c: PContext, n: PNode): char =
proc pragmaAsm*(c: PContext, n: PNode): char =
result = '\0'
if n != nil:
for i in countup(0, sonsLen(n) - 1):
if n != nil:
for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i]
if it.kind == nkExprColonExpr and it.sons[0].kind == nkIdent:
case whichKeyword(it.sons[0].ident)
of wSubsChar:
of wSubsChar:
if it.sons[1].kind == nkCharLit: result = chr(int(it.sons[1].intVal))
else: invalidPragma(it)
else: invalidPragma(it)
else:
else:
invalidPragma(it)
proc setExternName(s: PSym, extname: string) =
@@ -94,7 +94,7 @@ proc setExternName(s: PSym, extname: string) =
# note that '{.importc.}' is transformed into '{.importc: "$1".}'
s.loc.flags.incl(lfFullExternalName)
proc makeExternImport(s: PSym, extname: string) =
proc makeExternImport(s: PSym, extname: string) =
setExternName(s, extname)
incl(s.flags, sfImportc)
excl(s.flags, sfForward)
@@ -145,7 +145,7 @@ proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
result.strVal = ""
proc getStrLitNode(c: PContext, n: PNode): PNode =
if n.kind != nkExprColonExpr:
if n.kind != nkExprColonExpr:
localError(n.info, errStringLiteralExpected)
# error correction:
result = newEmptyStrNode(n)
@@ -153,62 +153,62 @@ proc getStrLitNode(c: PContext, n: PNode): PNode =
n.sons[1] = c.semConstExpr(c, n.sons[1])
case n.sons[1].kind
of nkStrLit, nkRStrLit, nkTripleStrLit: result = n.sons[1]
else:
else:
localError(n.info, errStringLiteralExpected)
# error correction:
result = newEmptyStrNode(n)
proc expectStrLit(c: PContext, n: PNode): string =
proc expectStrLit(c: PContext, n: PNode): string =
result = getStrLitNode(c, n).strVal
proc expectIntLit(c: PContext, n: PNode): int =
if n.kind != nkExprColonExpr:
proc expectIntLit(c: PContext, n: PNode): int =
if n.kind != nkExprColonExpr:
localError(n.info, errIntLiteralExpected)
else:
else:
n.sons[1] = c.semConstExpr(c, n.sons[1])
case n.sons[1].kind
of nkIntLit..nkInt64Lit: result = int(n.sons[1].intVal)
else: localError(n.info, errIntLiteralExpected)
proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
if n.kind == nkExprColonExpr: result = expectStrLit(c, n)
else: result = defaultStr
proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
sym.constraint = getStrLitNode(c, n)
proc processMagic(c: PContext, n: PNode, s: PSym) =
proc processMagic(c: PContext, n: PNode, s: PSym) =
#if sfSystemModule notin c.module.flags:
# liMessage(n.info, errMagicOnlyInSystem)
if n.kind != nkExprColonExpr:
if n.kind != nkExprColonExpr:
localError(n.info, errStringLiteralExpected)
return
var v: string
if n.sons[1].kind == nkIdent: v = n.sons[1].ident.s
else: v = expectStrLit(c, n)
for m in countup(low(TMagic), high(TMagic)):
if substr($m, 1) == v:
for m in countup(low(TMagic), high(TMagic)):
if substr($m, 1) == v:
s.magic = m
break
if s.magic == mNone: message(n.info, warnUnknownMagic, v)
proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
# this assumes that the order of special words and calling conventions is
# the same
result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))
proc isTurnedOn(c: PContext, n: PNode): bool =
proc isTurnedOn(c: PContext, n: PNode): bool =
if n.kind == nkExprColonExpr:
let x = c.semConstBoolExpr(c, n.sons[1])
n.sons[1] = x
if x.kind == nkIntLit: return x.intVal != 0
localError(n.info, errOnOrOffExpected)
proc onOff(c: PContext, n: PNode, op: TOptions) =
proc onOff(c: PContext, n: PNode, op: TOptions) =
if isTurnedOn(c, n): gOptions = gOptions + op
else: gOptions = gOptions - op
proc pragmaDeadCodeElim(c: PContext, n: PNode) =
proc pragmaDeadCodeElim(c: PContext, n: PNode) =
if isTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim)
else: excl(c.module.flags, sfDeadCodeElim)
@@ -216,20 +216,20 @@ proc pragmaNoForward(c: PContext, n: PNode) =
if isTurnedOn(c, n): incl(c.module.flags, sfNoForward)
else: excl(c.module.flags, sfNoForward)
proc processCallConv(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
proc processCallConv(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
var sw = whichKeyword(n.sons[1].ident)
case sw
of FirstCallConv..LastCallConv:
of FirstCallConv..LastCallConv:
POptionEntry(c.optionStack.tail).defaultCC = wordToCallConv(sw)
else: localError(n.info, errCallConvExpected)
else:
else:
localError(n.info, errCallConvExpected)
proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
var it = PLib(c.libs.head)
while it != nil:
if it.kind == kind:
while it != nil:
if it.kind == kind:
if trees.exprStructuralEquivalent(it.path, path): return it
it = PLib(it.next)
result = newLib(kind)
@@ -252,10 +252,10 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
localError(n.info, errStringLiteralExpected)
result = newEmptyStrNode(n)
proc processDynLib(c: PContext, n: PNode, sym: PSym) =
proc processDynLib(c: PContext, n: PNode, sym: PSym) =
if (sym == nil) or (sym.kind == skModule):
POptionEntry(c.optionStack.tail).dynlib = getLib(c, libDynamic,
POptionEntry(c.optionStack.tail).dynlib = getLib(c, libDynamic,
expectDynlibNode(c, n))
else:
if n.kind == nkExprColonExpr:
@@ -268,7 +268,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
# since we'll be loading the dynlib symbols dynamically, we must use
# a calling convention that doesn't introduce custom name mangling
# cdecl is the default - the user can override this explicitly
if sym.kind in routineKinds and sym.typ != nil and
if sym.kind in routineKinds and sym.typ != nil and
sym.typ.callConv == ccDefault:
sym.typ.callConv = ccCDecl
@@ -295,10 +295,10 @@ proc processNote(c: PContext, n: PNode) =
n.sons[1] = x
if x.kind == nkIntLit and x.intVal != 0: incl(gNotes, nk)
else: excl(gNotes, nk)
else:
else:
invalidPragma(n)
proc processOption(c: PContext, n: PNode): bool =
proc processOption(c: PContext, n: PNode): bool =
if n.kind != nkExprColonExpr: result = true
elif n.sons[0].kind == nkBracketExpr: processNote(c, n)
elif n.sons[0].kind != nkIdent: result = true
@@ -318,34 +318,34 @@ proc processOption(c: PContext, n: PNode): bool =
of wAssertions: onOff(c, n, {optAssert})
of wWarnings: onOff(c, n, {optWarns})
of wHints: onOff(c, n, {optHints})
of wCallconv: processCallConv(c, n)
of wCallconv: processCallConv(c, n)
of wLinedir: onOff(c, n, {optLineDir})
of wStacktrace: onOff(c, n, {optStackTrace})
of wLinetrace: onOff(c, n, {optLineTrace})
of wDebugger: onOff(c, n, {optEndb})
of wProfiler: onOff(c, n, {optProfiler})
of wByRef: onOff(c, n, {optByRef})
of wDynlib: processDynLib(c, n, nil)
of wOptimization:
if n.sons[1].kind != nkIdent:
of wDynlib: processDynLib(c, n, nil)
of wOptimization:
if n.sons[1].kind != nkIdent:
invalidPragma(n)
else:
else:
case n.sons[1].ident.s.normalize
of "speed":
of "speed":
incl(gOptions, optOptimizeSpeed)
excl(gOptions, optOptimizeSize)
of "size":
excl(gOptions, optOptimizeSpeed)
incl(gOptions, optOptimizeSize)
of "none":
of "none":
excl(gOptions, optOptimizeSpeed)
excl(gOptions, optOptimizeSize)
else: localError(n.info, errNoneSpeedOrSizeExpected)
of wImplicitStatic: onOff(c, n, {optImplicitStatic})
of wPatterns: onOff(c, n, {optPatterns})
else: result = true
proc processPush(c: PContext, n: PNode, start: int) =
proc processPush(c: PContext, n: PNode, start: int) =
if n.sons[start-1].kind == nkExprColonExpr:
localError(n.info, errGenerated, "':' after 'push' not supported")
var x = newOptionEntry()
@@ -355,41 +355,41 @@ proc processPush(c: PContext, n: PNode, start: int) =
x.dynlib = y.dynlib
x.notes = gNotes
append(c.optionStack, x)
for i in countup(start, sonsLen(n) - 1):
for i in countup(start, sonsLen(n) - 1):
if processOption(c, n.sons[i]):
# simply store it somewhere:
if x.otherPragmas.isNil:
x.otherPragmas = newNodeI(nkPragma, n.info)
x.otherPragmas.add n.sons[i]
#localError(n.info, errOptionExpected)
proc processPop(c: PContext, n: PNode) =
if c.optionStack.counter <= 1:
proc processPop(c: PContext, n: PNode) =
if c.optionStack.counter <= 1:
localError(n.info, errAtPopWithoutPush)
else:
gOptions = POptionEntry(c.optionStack.tail).options
else:
gOptions = POptionEntry(c.optionStack.tail).options
gNotes = POptionEntry(c.optionStack.tail).notes
remove(c.optionStack, c.optionStack.tail)
proc processDefine(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
proc processDefine(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
defineSymbol(n.sons[1].ident.s)
message(n.info, warnDeprecated, "define")
else:
else:
invalidPragma(n)
proc processUndef(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
proc processUndef(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
undefSymbol(n.sons[1].ident.s)
message(n.info, warnDeprecated, "undef")
else:
else:
invalidPragma(n)
type
TLinkFeature = enum
type
TLinkFeature = enum
linkNormal, linkSys
proc processCompile(c: PContext, n: PNode) =
proc processCompile(c: PContext, n: PNode) =
var s = expectStrLit(c, n)
var found = findFile(s)
if found == "": found = s
@@ -397,7 +397,7 @@ proc processCompile(c: PContext, n: PNode) =
extccomp.addExternalFileToCompile(found)
extccomp.addFileToLink(completeCFilePath(trunc, false))
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
var f = expectStrLit(c, n)
if splitFile(f).ext == "": f = addFileExt(f, CC[cCompiler].objExt)
var found = findFile(f)
@@ -407,8 +407,8 @@ proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
of linkSys:
extccomp.addFileToLink(libpath / completeCFilePath(found, false))
else: internalError(n.info, "processCommonLink")
proc pragmaBreakpoint(c: PContext, n: PNode) =
proc pragmaBreakpoint(c: PContext, n: PNode) =
discard getOptionalStr(c, n, "")
proc pragmaWatchpoint(c: PContext, n: PNode) =
@@ -427,59 +427,59 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
return
# now parse the string literal and substitute symbols:
var a = 0
while true:
while true:
var b = strutils.find(str, marker, a)
var sub = if b < 0: substr(str, a) else: substr(str, a, b - 1)
if sub != "": addSon(result, newStrNode(nkStrLit, sub))
if b < 0: break
if b < 0: break
var c = strutils.find(str, marker, b + 1)
if c < 0: sub = substr(str, b + 1)
else: sub = substr(str, b + 1, c - 1)
if sub != "":
if sub != "":
var e = searchInScopes(con, getIdent(sub))
if e != nil:
if e != nil:
if e.kind == skStub: loadStub(e)
addSon(result, newSymNode(e))
else:
else:
addSon(result, newStrNode(nkStrLit, sub))
else:
# an empty '``' produces a single '`'
addSon(result, newStrNode(nkStrLit, $marker))
if c < 0: break
if c < 0: break
a = c + 1
else:
illFormedAstLocal(n)
result = newNode(nkAsmStmt, n.info)
proc pragmaEmit(c: PContext, n: PNode) =
proc pragmaEmit(c: PContext, n: PNode) =
discard getStrLitNode(c, n)
n.sons[1] = semAsmOrEmit(c, n, '`')
proc noVal(n: PNode) =
proc noVal(n: PNode) =
if n.kind == nkExprColonExpr: invalidPragma(n)
proc pragmaUnroll(c: PContext, n: PNode) =
if c.p.nestedLoopCounter <= 0:
proc pragmaUnroll(c: PContext, n: PNode) =
if c.p.nestedLoopCounter <= 0:
invalidPragma(n)
elif n.kind == nkExprColonExpr:
var unrollFactor = expectIntLit(c, n)
if unrollFactor <% 32:
if unrollFactor <% 32:
n.sons[1] = newIntNode(nkIntLit, unrollFactor)
else:
else:
invalidPragma(n)
proc pragmaLine(c: PContext, n: PNode) =
if n.kind == nkExprColonExpr:
n.sons[1] = c.semConstExpr(c, n.sons[1])
let a = n.sons[1]
if a.kind == nkPar:
if a.kind == nkPar:
var x = a.sons[0]
var y = a.sons[1]
if x.kind == nkExprColonExpr: x = x.sons[1]
if y.kind == nkExprColonExpr: y = y.sons[1]
if x.kind != nkStrLit:
if x.kind != nkStrLit:
localError(n.info, errStringLiteralExpected)
elif y.kind != nkIntLit:
elif y.kind != nkIntLit:
localError(n.info, errIntLiteralExpected)
else:
n.info.fileIndex = msgs.fileInfoIdx(x.strVal)
@@ -490,12 +490,12 @@ proc pragmaLine(c: PContext, n: PNode) =
# sensible default:
n.info = getInfoContext(-1)
proc processPragma(c: PContext, n: PNode, i: int) =
proc processPragma(c: PContext, n: PNode, i: int) =
var it = n.sons[i]
if it.kind != nkExprColonExpr: invalidPragma(n)
elif it.sons[0].kind != nkIdent: invalidPragma(n)
elif it.sons[1].kind != nkIdent: invalidPragma(n)
var userPragma = newSym(skTemplate, it.sons[1].ident, nil, it.info)
var body = newNodeI(nkPragma, n.info)
for j in i+1 .. sonsLen(n)-1: addSon(body, n.sons[j])
@@ -508,7 +508,7 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
if t.kind != tyObject:
localError(x.info, errGenerated, "invalid type for raises/tags list")
x.typ = t
if n.kind == nkExprColonExpr:
let it = n.sons[1]
if it.kind notin {nkCurly, nkBracket}:
@@ -569,7 +569,7 @@ proc deprecatedStmt(c: PContext; pragma: PNode) =
localError(n.info, "key:value pair expected")
proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
if it.kind != nkExprColonExpr:
if it.kind != nkExprColonExpr:
invalidPragma(it); return
let n = it[1]
if n.kind == nkSym:
@@ -592,9 +592,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
if key.kind == nkIdent:
var userPragma = strTableGet(c.userPragmas, key.ident)
if userPragma != nil:
if userPragma != nil:
inc c.instCounter
if c.instCounter > 100:
if c.instCounter > 100:
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
pragma(c, sym, userPragma.ast, validPragmas)
# ensure the pragma is also remember for generic instantiations in other
@@ -603,9 +603,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
dec c.instCounter
else:
var k = whichKeyword(key.ident)
if k in validPragmas:
if k in validPragmas:
case k
of wExportc:
of wExportc:
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
incl(sym.flags, sfUsed) # avoid wrong hints
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"))
@@ -627,16 +627,16 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
var align = expectIntLit(c, it)
if (not isPowerOfTwo(align) and align != 0) or align >% high(int16):
localError(it.info, errPowerOfTwoExpected)
else:
else:
sym.typ.align = align.int16
of wSize:
if sym.typ == nil: invalidPragma(it)
var size = expectIntLit(c, it)
if not isPowerOfTwo(size) or size <= 0 or size > 8:
if not isPowerOfTwo(size) or size <= 0 or size > 8:
localError(it.info, errPowerOfTwoExpected)
else:
sym.typ.size = size
of wNodecl:
of wNodecl:
noVal(it)
incl(sym.loc.flags, lfNoDecl)
of wPure, wAsmNoStackFrame:
@@ -644,19 +644,19 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
if sym != nil:
if k == wPure and sym.kind in routineKinds: invalidPragma(it)
else: incl(sym.flags, sfPure)
of wVolatile:
of wVolatile:
noVal(it)
incl(sym.flags, sfVolatile)
of wRegister:
of wRegister:
noVal(it)
incl(sym.flags, sfRegister)
of wThreadVar:
of wThreadVar:
noVal(it)
incl(sym.flags, sfThread)
of wDeadCodeElim: pragmaDeadCodeElim(c, it)
of wNoForward: pragmaNoForward(c, it)
of wMagic: processMagic(c, it, sym)
of wCompileTime:
of wCompileTime:
noVal(it)
incl(sym.flags, sfCompileTime)
incl(sym.loc.flags, lfNoDecl)
@@ -664,15 +664,15 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it)
incl(sym.flags, sfGlobal)
incl(sym.flags, sfPure)
of wMerge:
of wMerge:
noVal(it)
incl(sym.flags, sfMerge)
of wHeader:
of wHeader:
var lib = getLib(c, libHeader, getStrLitNode(c, it))
addToLib(lib, sym)
incl(sym.flags, sfImportc)
incl(sym.loc.flags, lfHeader)
incl(sym.loc.flags, lfNoDecl)
incl(sym.loc.flags, lfNoDecl)
# implies nodecl, because otherwise header would not make sense
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
of wDestructor:
@@ -685,13 +685,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it)
incl(sym.flags, sfNoSideEffect)
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
of wSideeffect:
of wSideeffect:
noVal(it)
incl(sym.flags, sfSideEffect)
of wNoreturn:
of wNoreturn:
noVal(it)
incl(sym.flags, sfNoReturn)
of wDynlib:
of wDynlib:
processDynLib(c, it, sym)
of wCompilerproc:
noVal(it) # compilerproc may not get a string!
@@ -703,7 +703,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
if it.kind == nkExprColonExpr: deprecatedStmt(c, it)
elif sym != nil: incl(sym.flags, sfDeprecated)
else: incl(c.module.flags, sfDeprecated)
of wVarargs:
of wVarargs:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfVarargs)
@@ -713,7 +713,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
else:
noVal(it)
incl(sym.flags, sfBorrow)
of wFinal:
of wFinal:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfFinal)
@@ -745,10 +745,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
else: incl(sym.typ.flags, tfPacked)
of wHint: message(it.info, hintUser, expectStrLit(c, it))
of wWarning: message(it.info, warnUser, expectStrLit(c, it))
of wError:
of wError:
if sym != nil and sym.isRoutine:
# This is subtle but correct: the error *statement* is only
# allowed for top level statements. Seems to be easier than
# allowed for top level statements. Seems to be easier than
# distinguishing properly between
# ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
noVal(it)
@@ -765,11 +765,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wPassc: extccomp.addCompileOption(expectStrLit(c, it))
of wBreakpoint: pragmaBreakpoint(c, it)
of wWatchPoint: pragmaWatchpoint(c, it)
of wPush:
of wPush:
processPush(c, n, i + 1)
result = true
result = true
of wPop: processPop(c, it)
of wPragma:
of wPragma:
processPragma(c, n, i)
result = true
of wDiscardable:
@@ -779,16 +779,16 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it)
if sym != nil: incl(sym.flags, sfNoInit)
of wCodegenDecl: processCodegenDecl(c, it, sym)
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
wLinedir, wStacktrace, wLinetrace, wOptimization,
wCallconv,
wCallconv,
wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
wPatterns:
if processOption(c, it):
# calling conventions (boring...):
localError(it.info, errOptionExpected)
of FirstCallConv..LastCallConv:
of FirstCallConv..LastCallConv:
assert(sym != nil)
if sym.typ == nil: invalidPragma(it)
else: sym.typ.callConv = wordToCallConv(k)
@@ -843,14 +843,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wInjectStmt:
if it.kind != nkExprColonExpr:
localError(it.info, errExprExpected)
else:
else:
it.sons[1] = c.semExpr(c, it.sons[1])
of wExperimental:
noVal(it)
if isTopLevel(c):
c.module.flags.incl sfExperimental
else:
localError(it.info, "'experimental' pragma only valid as toplevel statement")
localError(it.info, "'experimental' pragma only valid as toplevel statement")
else: invalidPragma(it)
else: invalidPragma(it)
else: processNote(c, it)
@@ -884,7 +884,7 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
var key = if p.kind == nkExprColonExpr: p[0] else: p
if key.kind == nkIdent and whichKeyword(key.ident) == pragma:
return true
return false
proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =

View File

@@ -5,6 +5,7 @@ version 0.10.4
- make 'nil' work for 'add' and 'len'
- disallow negative indexing
- improve the parser; deal with echo $foo gotcha
- add "all threads are blocked" detection to 'spawn'
version 1.0