don't generate memset calls for C++ objects

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

View file

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

View file

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

View file

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