Merge branch 'devel' into feature/3691

This commit is contained in:
Dominik Picheta 2017-02-07 18:34:05 +01:00 • committed by GitHub
commit d5bb5e832b
84 changed files with 1381 additions and 492 deletions

View file

@ -1541,7 +1541,8 @@ proc skipGenericOwner*(s: PSym): PSym =
## Generic instantiations are owned by their originating generic
## symbol. This proc skips such owners and goes straight to the owner
## of the generic itself (the module or the enclosing proc).
result = if s.kind in skProcKinds and sfFromGeneric in s.flags:
result = if s.kind in skProcKinds and {sfGenSym, sfFromGeneric} * s.flags ==
{sfFromGeneric}:
s.owner.owner
else:
s.owner

View file

@ -1210,7 +1210,7 @@ proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
var elem, a, arr: TLoc
if t.kind == nkBracket:
if t.sons[1].kind == nkBracket:
t.sons[1].typ = t.typ
genSeqConstr(p, t.sons[1], d)
return
@ -1383,7 +1383,9 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
var a, b: TLoc
assert(d.k == locNone)
initLocExpr(p, e.sons[1], a)
var x = e.sons[1]
if x.kind in {nkAddr, nkHiddenAddr}: x = x[0]
initLocExpr(p, x, a)
initLocExpr(p, e.sons[2], b)
let t = skipTypes(e.sons[1].typ, {tyVar})
let setLenPattern = if not p.module.compileToCpp:
@ -2001,7 +2003,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
if sfThread in sym.flags:
accessThreadLocalVar(p, sym)
if emulatedThreadVars():
putIntoDest(p, d, sym.loc.t, "NimTV->" & sym.loc.r)
putIntoDest(p, d, sym.loc.t, "NimTV_->" & sym.loc.r)
else:
putLocIntoDest(p, d, sym.loc)
else:

View file

@ -64,7 +64,7 @@ proc genVarTuple(p: BProc, n: PNode) =
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
else:
if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)]
field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n.sons[i].sym, t)]
putLocIntoDest(p, v.loc, field)
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false)
@ -102,7 +102,7 @@ proc assignLabel(b: var TBlock): Rope {.inline.} =
proc blockBody(b: var TBlock): Rope =
result = b.sections[cpsLocals]
if b.frameLen > 0:
result.addf("FR.len+=$1;$n", [b.frameLen.rope])
result.addf("FR_.len+=$1;$n", [b.frameLen.rope])
result.add(b.sections[cpsInit])
result.add(b.sections[cpsStmts])
@ -123,7 +123,7 @@ proc endBlock(p: BProc) =
~"}$n"
let frameLen = p.blocks[topBlock].frameLen
if frameLen > 0:
blockEnd.addf("FR.len-=$1;$n", [frameLen.rope])
blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope])
endBlock(p, blockEnd)
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
@ -156,7 +156,7 @@ proc genGotoState(p: BProc, n: PNode) =
initLocExpr(p, n.sons[0], a)
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
p.beforeRetNeeded = true
lineF(p, cpsStmts, "case -1: goto BeforeRet;$n", [])
lineF(p, cpsStmts, "case -1: goto BeforeRet_;$n", [])
for i in 0 .. lastOrd(n.sons[0].typ):
lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [rope(i)])
lineF(p, cpsStmts, "}$n", [])
@ -373,7 +373,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
# consume it before we return.
var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
lineF(p, cpsStmts, "goto BeforeRet;$n", [])
lineF(p, cpsStmts, "goto BeforeRet_;$n", [])
proc genGotoForCase(p: BProc; caseStmt: PNode) =
for i in 1 .. <caseStmt.len:
@ -411,11 +411,11 @@ proc genComputedGoto(p: BProc; n: PNode) =
localError(n.info, "no case statement found for computed goto"); return
var id = p.labels+1
inc p.labels, arraySize+1
let tmp = "TMP$1" % [id.rope]
let tmp = "TMP$1_" % [id.rope]
var gotoArray = "static void* $#[$#] = {" % [tmp, arraySize.rope]
for i in 1..arraySize-1:
gotoArray.addf("&&TMP$#, ", [(id+i).rope])
gotoArray.addf("&&TMP$#};$n", [(id+arraySize).rope])
gotoArray.addf("&&TMP$#_, ", [(id+i).rope])
gotoArray.addf("&&TMP$#_};$n", [(id+arraySize).rope])
line(p, cpsLocals, gotoArray)
let topBlock = p.blocks.len-1
@ -445,7 +445,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
localError(it.info, "range notation not available for computed goto")
return
let val = getOrdValue(it.sons[j])
lineF(p, cpsStmts, "TMP$#:$n", [intLiteral(val+id+1)])
lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(val+id+1)])
genStmts(p, it.lastSon)
#for j in casePos+1 .. <n.len: genStmts(p, n.sons[j]) # tailB
#for j in 0 .. casePos-1: genStmts(p, n.sons[j]) # tailA
@ -600,7 +600,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
for i in 1..until:
# bug #4230: avoid false sharing between branches:
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
lineF(p, cpsStmts, "LA$1: ;$n", [rope(labId + i)])
lineF(p, cpsStmts, "LA$1_: ;$n", [rope(labId + i)])
if t.sons[i].kind == nkOfBranch:
var length = sonsLen(t.sons[i])
exprBlock(p, t.sons[i].sons[length - 1], d)
@ -618,15 +618,15 @@ proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
inc(p.labels)
if t.sons[i].kind == nkOfBranch: # else statement
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
"LA" & rope(p.labels))
"LA" & rope(p.labels) & "_")
else:
lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)])
if until < t.len-1:
inc(p.labels)
var gotoTarget = p.labels
lineF(p, cpsStmts, "goto LA$1;$n", [rope(gotoTarget)])
lineF(p, cpsStmts, "goto LA$1_;$n", [rope(gotoTarget)])
result = genCaseSecondPass(p, t, d, labId, until)
lineF(p, cpsStmts, "LA$1: ;$n", [rope(gotoTarget)])
lineF(p, cpsStmts, "LA$1_: ;$n", [rope(gotoTarget)])
else:
result = genCaseSecondPass(p, t, d, labId, until)
@ -664,7 +664,7 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
for i in countup(1, sonsLen(t) - 1):
inc(p.labels)
if t.sons[i].kind == nkOfBranch:
genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels),
genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels) & "_",
branches)
else:
# else statement: nothing to do yet
@ -678,7 +678,7 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
[intLiteral(j), branches[j]])
lineF(p, cpsStmts, "}$n", []) # else statement:
if t.sons[sonsLen(t)-1].kind != nkOfBranch:
lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)])
# third pass: generate statements
var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
fixLabel(p, lend)
@ -802,7 +802,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
let length = sonsLen(t)
endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
if optStackTrace in p.options:
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n")
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
inc p.inExceptBlock
var i = 1
var catchAllPresent = false
@ -910,7 +910,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
startBlock(p, "else {$n")
linefmt(p, cpsStmts, "#popSafePoint();$n")
if optStackTrace in p.options:
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n")
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
inc p.inExceptBlock
var i = 1
while (i < length) and (t.sons[i].kind == nkExceptBranch):

View file

@ -19,9 +19,9 @@ proc accessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars() and not p.threadVarAccessed:
p.threadVarAccessed = true
incl p.module.flags, usesThreadVars
addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", [])
addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV_;$n", [])
add(p.procSec(cpsInit),
ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n"))
ropecg(p.module, "\tNimTV_ = (NimThreadVars*) #GetThreadLocalVars();$n"))
var
nimtv: Rope # Nim thread vars; the struct body

View file

@ -145,7 +145,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
if sfThread in s.flags and emulatedThreadVars():
accessThreadLocalVar(p, s)
sLoc = "NimTV->" & sLoc
sLoc = "NimTV_->" & sLoc
c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
c.p = p

View file

@ -22,12 +22,10 @@ proc isKeyword(w: PIdent): bool =
ord(wInline): return true
else: return false
proc mangleField(name: PIdent): string =
proc mangleField(m: BModule; name: PIdent): string =
result = mangle(name.s)
if isKeyword(name):
result[0] = result[0].toUpperAscii
# Mangling makes everything lowercase,
# but some identifiers are C keywords
if isKeyword(name) or m.g.config.cppDefines.contains(result):
result.add "_0"
when false:
proc hashOwner(s: PSym): SigHash =
@ -67,55 +65,50 @@ proc idOrSig(m: BModule; s: PSym): Rope =
proc mangleName(m: BModule; s: PSym): Rope =
result = s.loc.r
if result == nil:
let keepOrigName = s.kind in skLocalVars - {skForVar} and
{sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
not isKeyword(s.name)
# Even with all these inefficient checks, the bootstrap
# time is actually improved. This is probably because so many
# rope concatenations are now eliminated.
#
# sfFromGeneric is needed in order to avoid multiple
# definitions of certain variables generated in transf with
# names such as:
# `r`, `res`
# I need to study where these come from.
#
# about sfShadowed:
# consider the following Nim code:
# var x = 10
# block:
# var x = something(x)
# The generated C code will be:
# NI x;
# x = 10;
# {
# NI x;
# x = something(x); // Oops, x is already shadowed here
# }
# Right now, we work-around by not keeping the original name
# of the shadowed variable, but we can do better - we can
# create an alternative reference to it in the outer scope and
# use that in the inner scope.
#
# about isCKeyword:
# Nim variable names can be C keywords.
# We need to avoid such names in the generated code.
#
# about sfGlobal:
# This seems to be harder - a top level extern variable from
# another modules can have the same name as a local one.
# Maybe we should just implement sfShadowed for them too.
#
# about skForVar:
# These are not properly scoped now - we need to add blocks
# around for loops in transf
result = s.name.s.mangle.rope
if keepOrigName:
result.add "0"
else:
add(result, m.idOrSig(s))
add(result, m.idOrSig(s))
s.loc.r = result
writeMangledName(m.ndi, s)
proc mangleParamName(m: BModule; s: PSym): Rope =
## we cannot use 'sigConflicts' here since we have a BModule, not a BProc.
## Fortunately C's scoping rules are sane enough so that that doesn't
## cause any trouble.
result = s.loc.r
if result == nil:
var res = s.name.s.mangle
if isKeyword(s.name) or m.g.config.cppDefines.contains(res):
res.add "_0"
result = res.rope
s.loc.r = result
writeMangledName(m.ndi, s)
proc mangleLocalName(p: BProc; s: PSym): Rope =
assert s.kind in skLocalVars+{skTemp}
assert sfGlobal notin s.flags
result = s.loc.r
if result == nil:
var key = s.name.s.mangle
shallow(key)
let counter = p.sigConflicts.getOrDefault(key)
result = key.rope
if s.kind == skTemp:
# speed up conflict search for temps (these are quite common):
if counter != 0: result.add "_" & rope(counter+1)
elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(key):
result.add "_" & rope(counter+1)
p.sigConflicts.inc(key)
s.loc.r = result
if s.kind != skTemp: writeMangledName(p.module.ndi, s)
proc scopeMangledParam(p: BProc; param: PSym) =
## parameter generation only takes BModule, not a BProc, so we have to
## remember these parameter names are already in scope to be able to
## generate unique identifiers reliably (consider that ``var a = a`` is
## even an idiom in Nim).
var key = param.name.s.mangle
shallow(key)
p.sigConflicts.inc(key)
const
irrelevantForBackend = {tyGenericBody, tyGenericInst, tyGenericInvocation,
@ -393,7 +386,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
var param = t.n.sons[i].sym
if isCompileTimeOnly(param.typ): continue
if params != nil: add(params, ~", ")
fillLoc(param.loc, locParam, param.typ, mangleName(m, param),
fillLoc(param.loc, locParam, param.typ, mangleParamName(m, param),
param.paramStorageLoc)
if ccgIntroducedPtr(param):
add(params, getTypeDescWeak(m, param.typ, check))
@ -436,12 +429,12 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
else: add(params, ")")
params = "(" & params
proc mangleRecFieldName(field: PSym, rectype: PType): Rope =
proc mangleRecFieldName(m: BModule; field: PSym, rectype: PType): Rope =
if (rectype.sym != nil) and
({sfImportc, sfExportc} * rectype.sym.flags != {}):
result = field.loc.r
else:
result = rope(mangleField(field.name))
result = rope(mangleField(m, field.name))
if result == nil: internalError(field.info, "mangleRecFieldName")
proc genRecordFieldsAux(m: BModule, n: PNode,
@ -480,7 +473,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
let field = n.sym
if field.typ.kind == tyVoid: return
#assert(field.ast == nil)
let sname = mangleRecFieldName(field, rectype)
let sname = mangleRecFieldName(m, field, rectype)
let ae = if accessExpr != nil: "$1.$2" % [accessExpr, sname]
else: sname
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
@ -1103,13 +1096,11 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode")
addf(m.s[cfsVars], "extern TNimType $1;$n", [result])
#return "(&".rope & result & ")".rope
#result = "NTI$1" % [rope($sig)]
# also store in local type section:
m.typeInfoMarker[sig] = result
return "(&".rope & result & ")".rope
result = "NTI$1" % [rope($sig)]
result = "NTI$1_" % [rope($sig)]
m.typeInfoMarker[sig] = result
let owner = t.skipTypes(typedescPtrs).owner.getModule

View file

@ -164,28 +164,50 @@ proc makeSingleLineCString*(s: string): string =
result.add('\"')
proc mangle*(name: string): string =
## Lowercases the given name and manges any non-alphanumeric characters
## so they are represented as `HEX____`. If the name starts with a number,
## `N` is prepended
result = newStringOfCap(name.len)
case name[0]
of Letters:
result.add(name[0])
of Digits:
result.add("N" & name[0])
else:
result = "HEX" & toHex(ord(name[0]), 2)
for i in 1..(name.len-1):
var start = 0
if name[0] in Digits:
result.add("X" & name[0])
start = 1
var requiresUnderscore = false
template special(x) =
result.add x
requiresUnderscore = true
for i in start..(name.len-1):
let c = name[i]
case c
of 'A'..'Z':
add(result, c.toLowerAscii)
of '_':
discard
of 'a'..'z', '0'..'9':
of 'a'..'z', '0'..'9', 'A'..'Z':
add(result, c)
of '_':
# we generate names like 'foo_9' for scope disambiguations and so
# disallow this here:
if i < name.len-1 and name[i] in Digits:
discard
else:
add(result, c)
of '$': special "dollar"
of '%': special "percent"
of '&': special "amp"
of '^': special "roof"
of '!': special "emark"
of '?': special "qmark"
of '*': special "star"
of '+': special "plus"
of '-': special "minus"
of '/': special "slash"
of '=': special "eq"
of '<': special "lt"
of '>': special "gt"
of '~': special "tilde"
of ':': special "colon"
of '.': special "dot"
of '@': special "at"
of '|': special "bar"
else:
add(result, "HEX" & toHex(ord(c), 2))
add(result, "X" & toHex(ord(c), 2))
requiresUnderscore = true
if requiresUnderscore:
result.add "_"
proc makeLLVMString*(s: string): Rope =
const MaxLineLength = 64

View file

@ -14,7 +14,7 @@ import
nversion, nimsets, msgs, securehash, bitsets, idents, lists, types,
ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
lowerings, semparallel, tables
lowerings, semparallel, tables, sets, ndi
import strutils except `%` # collides with ropes.`%`
@ -216,7 +216,7 @@ proc genLineDir(p: BProc, t: PNode) =
{optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex >= 0:
if freshLineInfo(p, tt.info):
linefmt(p, cpsStmts, "nimln($1, $2);$n",
linefmt(p, cpsStmts, "nimln_($1, $2);$n",
line.rope, tt.info.quotedFilename)
proc postStmtActions(p: BProc) {.inline.} =
@ -338,7 +338,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
inc(p.labels)
result.r = "LOC" & rope(p.labels)
result.r = "T" & rope(p.labels) & "_"
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
result.k = locTemp
result.t = t
@ -347,12 +347,12 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
constructLoc(p, result, not needsInit)
proc initGCFrame(p: BProc): Rope =
if p.gcFrameId > 0: result = "struct {$1} GCFRAME;$n" % [p.gcFrameType]
if p.gcFrameId > 0: result = "struct {$1} GCFRAME_;$n" % [p.gcFrameType]
proc deinitGCFrame(p: BProc): Rope =
if p.gcFrameId > 0:
result = ropecg(p.module,
"if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n")
"if (((NU)&GCFRAME_) < 4096) #nimGCFrame(&GCFRAME_);$n")
proc localDebugInfo(p: BProc, s: PSym) =
if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
@ -361,7 +361,7 @@ proc localDebugInfo(p: BProc, s: PSym) =
var a = "&" & s.loc.r
if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r
lineF(p, cpsInit,
"FR.s[$1].address = (void*)$3; FR.s[$1].typ = $4; FR.s[$1].name = $2;$n",
"FR_.s[$1].address = (void*)$3; FR_.s[$1].typ = $4; FR_.s[$1].name = $2;$n",
[p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
genTypeInfo(p.module, s.loc.t)])
inc(p.maxFrameLen)
@ -369,7 +369,7 @@ proc localDebugInfo(p: BProc, s: PSym) =
proc localVarDecl(p: BProc; s: PSym): Rope =
if s.loc.k == locNone:
fillLoc(s.loc, locLocalVar, s.typ, mangleName(p.module, s), OnStack)
fillLoc(s.loc, locLocalVar, s.typ, mangleLocalName(p, s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
result = getTypeDesc(p.module, s.typ)
if s.constraint.isNil:
@ -434,6 +434,7 @@ proc assignGlobalVar(p: BProc, s: PSym) =
proc assignParam(p: BProc, s: PSym) =
assert(s.loc.r != nil)
scopeMangledParam(p, s)
localDebugInfo(p, s)
proc fillProcLoc(m: BModule; sym: PSym) =
@ -442,7 +443,7 @@ proc fillProcLoc(m: BModule; sym: PSym) =
proc getLabel(p: BProc): TLabel =
inc(p.labels)
result = "LA" & rope(p.labels)
result = "LA" & rope(p.labels) & "_"
proc fixLabel(p: BProc, labl: TLabel) =
lineF(p, cpsStmts, "$1: ;$n", [labl])
@ -520,7 +521,7 @@ proc mangleDynLibProc(sym: PSym): Rope =
# NOTE: sym.loc.r is the external name!
result = rope(sym.name.s)
else:
result = "Dl_$1" % [rope(sym.id)]
result = "Dl_$1_" % [rope(sym.id)]
proc symInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
@ -608,11 +609,11 @@ proc initFrame(p: BProc, procname, filename: Rope): Rope =
discard cgsym(p.module, "nimFrame")
if p.maxFrameLen > 0:
discard cgsym(p.module, "VarSlot")
result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4)$N",
procname, filename, p.maxFrameLen.rope,
p.blocks[0].frameLen.rope)
else:
result = rfmt(nil, "\tnimfr($1, $2)$N", procname, filename)
result = rfmt(nil, "\tnimfr_($1, $2)$N", procname, filename)
proc deinitFrame(p: BProc): Rope =
result = rfmt(p.module, "\t#popFrame();$n")
@ -707,7 +708,7 @@ proc genProcAux(m: BModule, prc: PSym) =
if p.beforeRetNeeded: add(generatedProc, "{")
add(generatedProc, p.s(cpsInit))
add(generatedProc, p.s(cpsStmts))
if p.beforeRetNeeded: add(generatedProc, ~"\t}BeforeRet: ;$n")
if p.beforeRetNeeded: add(generatedProc, ~"\t}BeforeRet_: ;$n")
add(generatedProc, deinitGCFrame(p))
if optStackTrace in prc.options: add(generatedProc, deinitFrame(p))
add(generatedProc, returnStmt)
@ -846,7 +847,8 @@ proc genVarPrototype(m: BModule, sym: PSym) =
genVarPrototypeAux(m, sym)
proc addIntTypes(result: var Rope) {.inline.} =
addf(result, "#define NIM_INTBITS $1" & tnl, [
addf(result, "#define NIM_NEW_MANGLING_RULES" & tnl &
"#define NIM_INTBITS $1" & tnl, [
platform.CPU[targetCPU].intSize.rope])
proc getCopyright(cfile: Cfile): Rope =
@ -1058,7 +1060,7 @@ proc genInitCode(m: BModule) =
var procname = makeCString(m.module.name.s)
add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
else:
add(prc, ~"\tTFrame FR; FR.len = 0;$N")
add(prc, ~"\tTFrame FR_; FR_.len = 0;$N")
add(prc, genSectionStart(cpsInit))
add(prc, m.preInitProc.s(cpsInit))
@ -1123,7 +1125,7 @@ proc initProcOptions(m: BModule): TOptions =
proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
new(result)
result.tmpBase = rope("T" & $hashOwner(module) & "_")
result.tmpBase = rope("TM" & $hashOwner(module) & "_")
initLinkedList(result.headerFiles)
result.declaredThings = initIntSet()
result.declaredProtos = initIntSet()
@ -1150,6 +1152,9 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
incl result.flags, preventStackTrace
excl(result.preInitProc.options, optStackTrace)
excl(result.postInitProc.options, optStackTrace)
let ndiName = if optCDebug in gGlobalOptions: changeFileExt(completeCFilePath(filename), "ndi")
else: ""
open(result.ndi, ndiName)
proc nullify[T](arr: var T) =
for i in low(arr)..high(arr):
@ -1212,16 +1217,16 @@ proc newModule(g: BModuleList; module: PSym): BModule =
if (sfDeadCodeElim in module.flags):
internalError("added pending module twice: " & module.filename)
template injectG() {.dirty.} =
template injectG(config) {.dirty.} =
if graph.backend == nil:
graph.backend = newModuleList()
graph.backend = newModuleList(config)
let g = BModuleList(graph.backend)
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
injectG()
injectG(graph.config)
result = newModule(g, module)
if optGenIndex in gGlobalOptions and g.generatedHeader == nil:
let f = if headerFile.len > 0: headerFile else: gProjectFull
let f = if graph.config.headerFile.len > 0: graph.config.headerFile else: gProjectFull
g.generatedHeader = rawNewModule(g, module,
changeFileExt(completeCFilePath(f), hExt))
incl g.generatedHeader.flags, isHeaderFile
@ -1258,7 +1263,7 @@ proc getCFile(m: BModule): string =
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext)
proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
injectG()
injectG(graph.config)
assert optSymbolFiles in gGlobalOptions
var m = newModule(g, module)
readMergeInfo(getCFile(m), m)
@ -1341,6 +1346,7 @@ proc writeModule(m: BModule, pending: bool) =
var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
if not existsFile(cf.obj): cf.flags = {CfileFlag.Cached}
addFileToCompile(cf)
close(m.ndi)
proc updateCachedModule(m: BModule) =
let cfile = getCFile(m)
@ -1373,11 +1379,12 @@ proc myClose(b: PPassContext, n: PNode): PNode =
for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
genMainProc(m)
proc cgenWriteModules*(backend: RootRef) =
proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
let g = BModuleList(backend)
# we need to process the transitive closure because recursive module
# deps are allowed (and the system module is processed in the wrong
# order anyway)
g.config = config
if g.generatedHeader != nil: finishModule(g.generatedHeader)
while g.forwardedProcsCounter > 0:
for m in cgenModules(g):

View file

@ -11,7 +11,7 @@
import
ast, astalgo, ropes, passes, options, intsets, lists, platform, sighashes,
tables
tables, ndi
from msgs import TLineInfo
@ -56,7 +56,7 @@ type
BProc* = ref TCProc
TBlock*{.final.} = object
id*: int # the ID of the label; positive means that it
label*: Rope # generated text for the label
label*: Rope # generated text for the label
# nil if label is not used
sections*: TCProcSections # the code beloging
isLoop*: bool # whether block is a loop
@ -76,7 +76,7 @@ type
# leaving such scopes by raise or by return must
# execute any applicable finally blocks
finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when
# using return in finally statements
# using return in finally statements
labels*: Natural # for generating unique labels in the C proc
blocks*: seq[TBlock] # nested blocks
breakIdx*: int # the block that will be exited
@ -92,6 +92,7 @@ type
# (yes, C++ is weird like that)
gcFrameId*: Natural # for the GC stack marking
gcFrameType*: Rope # the struct {} we put the GC markers into
sigConflicts*: CountTable[string]
TTypeSeq* = seq[PType]
TypeCache* = Table[SigHash, Rope]
@ -115,6 +116,7 @@ type
breakPointId*: int
breakpoints*: Rope # later the breakpoints are inserted into the main proc
typeInfoMarker*: TypeCache
config*: ConfigRef
TCGen = object of TPassContext # represents a C source file
s*: TCFileSections # sections of the C file
@ -144,6 +146,7 @@ type
injectStmt*: Rope
sigConflicts*: CountTable[SigHash]
g*: BModuleList
ndi*: NdiFile
proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
# section in the current block
@ -162,9 +165,10 @@ proc newProc*(prc: PSym, module: BModule): BProc =
newSeq(result.blocks, 1)
result.nestedTryStmts = @[]
result.finallySafePoints = @[]
result.sigConflicts = initCountTable[string]()
proc newModuleList*(): BModuleList =
BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope]())
proc newModuleList*(config: ConfigRef): BModuleList =
BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: config)
iterator cgenModules*(g: BModuleList): BModule =
for i in 0..high(g.modules):

View file

@ -47,7 +47,8 @@ type
passPP # preprocessor called processCommand()
proc processCommand*(switch: string, pass: TCmdLinePass)
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
config: ConfigRef = nil)
# implementation
@ -312,7 +313,8 @@ proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
expectArg(switch, arg, pass, info)
options.inclDynlibOverride(arg)
proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
config: ConfigRef = nil) =
var
theOS: TSystemOS
cpu: TSystemCPU
@ -509,10 +511,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
of "passc", "t":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg)
if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(arg)
of "passl", "l":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(arg)
of "cincludes":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: cIncludes.add arg.processPath(info)
@ -523,7 +525,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info)
of "header":
headerFile = arg
if config != nil: config.headerFile = arg
incl(gGlobalOptions, optGenIndex)
of "index":
processOnOffSwitchG({optGenIndex}, arg, pass, info)
@ -646,6 +648,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optNoCppExceptions)
defineSymbol("noCppExceptions")
of "cppdefine":
expectArg(switch, arg, pass, info)
if config != nil:
config.cppDefine(arg)
else:
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
else: invalidCmdLineOption(pass, switch, info)

View file

@ -101,3 +101,4 @@ proc initDefines*() =
defineSymbol("nimImmediateDeprecated")
defineSymbol("nimNewShiftOps")
defineSymbol("nimDistros")
defineSymbol("nimHasCppDefine")

View file

@ -209,26 +209,26 @@ proc getPlainDocstring(n: PNode): string =
result = getPlainDocstring(n.sons[i])
if result.len > 0: return
when false:
proc findDocComment(n: PNode): PNode =
if n == nil: return nil
if not isNil(n.comment) and startsWith(n.comment, "##"): return n
for i in countup(0, safeLen(n)-1):
result = findDocComment(n.sons[i])
if result != nil: return
proc findDocComment(n: PNode): PNode =
if n == nil: return nil
if not isNil(n.comment) and startsWith(n.comment, "##"): return n
for i in countup(0, safeLen(n)-1):
result = findDocComment(n.sons[i])
if result != nil: return
proc extractDocComment*(s: PSym, d: PDoc = nil): string =
let n = findDocComment(s.ast)
result = ""
if not n.isNil:
if not d.isNil:
var dummyHasToc: bool
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options + {roSkipPounds}),
result)
else:
result = n.comment.substr(2).replace("\n##", "\n").strip
proc extractDocComment*(s: PSym, d: PDoc = nil): string =
let n = findDocComment(s.ast)
result = ""
if not n.isNil:
if not d.isNil:
var dummyHasToc: bool
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options + {roSkipPounds}),
result)
else:
result = n.comment.substr(2).replace("\n##", "\n").strip
proc isVisible(n: PNode): bool =
result = false

View file

@ -392,6 +392,8 @@ type
var
externalToLink: TLinkedList # files to link in addition to the file
# we compiled
linkOptionsCmd: string = ""
compileOptionsCmd: seq[string] = @[]
linkOptions: string = ""
compileOptions: string = ""
ccompilerpath: string = ""
@ -450,6 +452,12 @@ proc addCompileOption*(option: string) =
if strutils.find(compileOptions, option, 0) < 0:
addOpt(compileOptions, option)
proc addLinkOptionCmd*(option: string) =
addOpt(linkOptionsCmd, option)
proc addCompileOptionCmd*(option: string) =
compileOptionsCmd.add(option)
proc initVars*() =
# we need to define the symbol here, because ``CC`` may have never been set!
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
@ -524,6 +532,10 @@ proc add(s: var string, many: openArray[string]) =
proc cFileSpecificOptions(cfilename: string): string =
result = compileOptions
for option in compileOptionsCmd:
if strutils.find(result, option, 0) < 0:
addOpt(result, option)
var trunk = splitFile(cfilename).name
if optCDebug in gGlobalOptions:
var key = trunk & ".debug"
@ -544,7 +556,7 @@ proc getCompileOptions: string =
result = cFileSpecificOptions("__dummy__")
proc getLinkOptions: string =
result = linkOptions
result = linkOptions & " " & linkOptionsCmd & " "
for linkedLib in items(cLinkedLibs):
result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell)
for libDir in items(cLibs):

View file

@ -46,7 +46,7 @@ Start: "doc/html/overview.html"
[Other]
Files: "readme.txt;install.txt;contributors.txt;copying.txt"
Files: "readme.txt;copying.txt"
Files: "makefile"
Files: "koch.nim"
Files: "install_nimble.nims"
@ -94,15 +94,17 @@ Files: "bin/vccexe.exe"
Files: "koch.exe"
Files: "finish.exe"
Files: "downloader.exe"
; Files: "dist/mingw"
Files: r"tools\start.bat"
BinPath: r"bin;dist\mingw\bin;dist"
; Section | dir | zipFile | size hint (in KB) | url | exe start menu entry
Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|overview.html"
Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip"
Download: r"Support DLLs|bin|nim_dlls.zip|479|http://nim-lang.org/download/dlls.zip"
Download: r"Aporia Text Editor|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.4.0.zip|aporia-0.4.0\bin\aporia.exe"
Download: r"Documentation|doc|docs.zip|13824|https://nim-lang.org/download/docs-${version}.zip|overview.html"
Download: r"C Compiler (MingW)|dist|mingw.zip|82944|https://nim-lang.org/download/${mingw}.zip"
Download: r"Support DLLs|bin|nim_dlls.zip|479|https://nim-lang.org/download/dlls.zip"
Download: r"Aporia Text Editor|dist|aporia.zip|97997|https://nim-lang.org/download/aporia-0.4.0.zip|aporia-0.4.0\bin\aporia.exe"
; for now only NSIS supports optional downloads
[WinBin]

View file

@ -72,7 +72,7 @@ proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
#registerPass(cleanupPass())
compileProject(graph, cache)
cgenWriteModules(graph.backend)
cgenWriteModules(graph.backend, graph.config)
if gCmd != cmdRun:
let proj = changeFileExt(gProjectFull, "")
extccomp.callCCompiler(proj)
@ -294,4 +294,4 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
resetAttributes()
proc mainCommand*() = mainCommand(newModuleGraph(), newIdentCache())
proc mainCommand*() = mainCommand(newModuleGraph(newConfigRef()), newIdentCache())

View file

@ -25,7 +25,7 @@
## - Its dependent module stays the same.
##
import ast, intsets, tables
import ast, intsets, tables, options
type
ModuleGraph* = ref object
@ -39,16 +39,21 @@ type
importStack*: seq[int32] # The current import stack. Used for detecting recursive
# module dependencies.
backend*: RootRef # minor hack so that a backend can extend this easily
config*: ConfigRef
{.this: g.}
proc newModuleGraph*(): ModuleGraph =
proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph =
result = ModuleGraph()
initStrTable(result.packageSyms)
result.deps = initIntSet()
result.modules = @[]
result.importStack = @[]
result.inclToMod = initTable[int32, int32]()
if config.isNil:
result.config = newConfigRef()
else:
result.config = config
proc resetAllModules*(g: ModuleGraph) =
initStrTable(packageSyms)

View file

@ -12,7 +12,7 @@ import
type
TMsgKind* = enum
errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated,
errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated,
errXCompilerDoesNotSupportCpp, errStringLiteralExpected,
errIntLiteralExpected, errInvalidCharacterConstant,
errClosingTripleQuoteExpected, errClosingQuoteExpected,
@ -135,8 +135,8 @@ type
const
MsgKindToStr*: array[TMsgKind, string] = [
errUnknown: "unknown error",
errIllFormedAstX: "illformed AST: $1",
errInternal: "internal error: $1",
errIllFormedAstX: "illformed AST: $1",
errCannotOpenFile: "cannot open \'$1\'",
errGenerated: "$1",
errXCompilerDoesNotSupportCpp: "\'$1\' compiler does not support C++",

40
compiler/ndi.nim Normal file
View file

@ -0,0 +1,40 @@
#
#
# The Nim Compiler
# (c) Copyright 2017 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements the generation of ``.ndi`` files for better debugging
## support of Nim code. "ndi" stands for "Nim debug info".
import ast, msgs, ropes
type
NdiFile* = object
enabled: bool
f: File
buf: string
proc doWrite(f: var NdiFile; s: PSym) =
f.buf.setLen 0
f.buf.add s.info.line.int
f.buf.add "\t"
f.buf.add s.info.col.int
f.f.write(s.name.s, "\t")
f.f.writeRope(s.loc.r)
f.f.writeLine("\t", s.info.toFullPath, "\t", f.buf)
template writeMangledName*(f: NdiFile; s: PSym) =
if f.enabled: doWrite(f, s)
proc open*(f: var NdiFile; filename: string) =
f.enabled = filename.len > 0
if f.enabled:
f.f = open(filename, fmWrite, 8000)
f.buf = newStringOfCap(20)
proc close*(f: var NdiFile) =
if f.enabled: close(f.f)

View file

@ -37,7 +37,7 @@ proc prependCurDir(f: string): string =
else:
result = f
proc handleCmdLine(cache: IdentCache) =
proc handleCmdLine(cache: IdentCache; config: ConfigRef) =
if paramCount() == 0:
writeCommandLineUsage()
else:
@ -59,22 +59,22 @@ proc handleCmdLine(cache: IdentCache) =
gProjectName = p.name
else:
gProjectPath = canonicalizePath getCurrentDir()
loadConfigs(DefaultConfig) # load all config files
loadConfigs(DefaultConfig, config) # load all config files
let scriptFile = gProjectFull.changeFileExt("nims")
if fileExists(scriptFile):
runNimScript(cache, scriptFile, freshDefines=false)
runNimScript(cache, scriptFile, freshDefines=false, config)
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
if scriptFile == gProjectFull: return
elif fileExists(gProjectPath / "config.nims"):
# directory wide NimScript file
runNimScript(cache, gProjectPath / "config.nims", freshDefines=false)
runNimScript(cache, gProjectPath / "config.nims", freshDefines=false, config)
# now process command line arguments again, because some options in the
# command line can overwite the config file's settings
extccomp.initVars()
processCmdLine(passCmd2, "")
if options.command == "":
rawMessage(errNoCommand, command)
mainCommand(newModuleGraph(), cache)
mainCommand(newModuleGraph(config), cache)
if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics())
#echo(GC_getStatistics())
if msgs.gErrorCounter == 0:
@ -118,5 +118,5 @@ when compileOption("gc", "v2") or compileOption("gc", "refc"):
condsyms.initDefines()
when not defined(selftest):
handleCmdLine(newIdentCache())
handleCmdLine(newIdentCache(), newConfigRef())
msgQuit(int8(msgs.gErrorCounter > 0))

View file

@ -21,37 +21,37 @@ proc ppGetTok(L: var TLexer, tok: var TToken) =
rawGetTok(L, tok)
while tok.tokType in {tkComment}: rawGetTok(L, tok)
proc parseExpr(L: var TLexer, tok: var TToken): bool
proc parseAtom(L: var TLexer, tok: var TToken): bool =
proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool
proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
if tok.tokType == tkParLe:
ppGetTok(L, tok)
result = parseExpr(L, tok)
result = parseExpr(L, tok, config)
if tok.tokType == tkParRi: ppGetTok(L, tok)
else: lexMessage(L, errTokenExpected, "\')\'")
elif tok.ident.id == ord(wNot):
ppGetTok(L, tok)
result = not parseAtom(L, tok)
result = not parseAtom(L, tok, config)
else:
result = isDefined(tok.ident)
ppGetTok(L, tok)
proc parseAndExpr(L: var TLexer, tok: var TToken): bool =
result = parseAtom(L, tok)
proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
result = parseAtom(L, tok, config)
while tok.ident.id == ord(wAnd):
ppGetTok(L, tok) # skip "and"
var b = parseAtom(L, tok)
var b = parseAtom(L, tok, config)
result = result and b
proc parseExpr(L: var TLexer, tok: var TToken): bool =
result = parseAndExpr(L, tok)
proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
result = parseAndExpr(L, tok, config)
while tok.ident.id == ord(wOr):
ppGetTok(L, tok) # skip "or"
var b = parseAndExpr(L, tok)
var b = parseAndExpr(L, tok, config)
result = result or b
proc evalppIf(L: var TLexer, tok: var TToken): bool =
proc evalppIf(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
ppGetTok(L, tok) # skip 'if' or 'elif'
result = parseExpr(L, tok)
result = parseExpr(L, tok, config)
if tok.tokType == tkColon: ppGetTok(L, tok)
else: lexMessage(L, errTokenExpected, "\':\'")
@ -66,20 +66,20 @@ type
TJumpDest = enum
jdEndif, jdElseEndif
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest)
proc doElse(L: var TLexer, tok: var TToken) =
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef)
proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef) =
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
ppGetTok(L, tok)
if tok.tokType == tkColon: ppGetTok(L, tok)
if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif)
if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config)
proc doElif(L: var TLexer, tok: var TToken) =
proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef) =
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
var res = evalppIf(L, tok)
if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif)
var res = evalppIf(L, tok, config)
if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config)
else: condStack[high(condStack)] = true
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef) =
var nestedIfs = 0
while true:
if tok.ident != nil and tok.ident.s == "@":
@ -89,11 +89,11 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
inc(nestedIfs)
of wElse:
if dest == jdElseEndif and nestedIfs == 0:
doElse(L, tok)
doElse(L, tok, config)
break
of wElif:
if dest == jdElseEndif and nestedIfs == 0:
doElif(L, tok)
doElif(L, tok, config)
break
of wEnd:
if nestedIfs == 0:
@ -108,16 +108,16 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
else:
ppGetTok(L, tok)
proc parseDirective(L: var TLexer, tok: var TToken) =
proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef) =
ppGetTok(L, tok) # skip @
case whichKeyword(tok.ident)
of wIf:
setLen(condStack, len(condStack) + 1)
let res = evalppIf(L, tok)
let res = evalppIf(L, tok, config)
condStack[high(condStack)] = res
if not res: jumpToDirective(L, tok, jdElseEndif)
of wElif: doElif(L, tok)
of wElse: doElse(L, tok)
if not res: jumpToDirective(L, tok, jdElseEndif, config)
of wElif: doElif(L, tok, config)
of wElse: doElse(L, tok, config)
of wEnd: doEnd(L, tok)
of wWrite:
ppGetTok(L, tok)
@ -146,58 +146,58 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
ppGetTok(L, tok)
else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
proc confTok(L: var TLexer, tok: var TToken) =
proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef) =
ppGetTok(L, tok)
while tok.ident != nil and tok.ident.s == "@":
parseDirective(L, tok) # else: give the token to the parser
parseDirective(L, tok, config) # else: give the token to the parser
proc checkSymbol(L: TLexer, tok: TToken) =
if tok.tokType notin {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}:
lexMessage(L, errIdentifierExpected, tokToStr(tok))
proc parseAssignment(L: var TLexer, tok: var TToken) =
proc parseAssignment(L: var TLexer, tok: var TToken; config: ConfigRef) =
if tok.ident.s == "-" or tok.ident.s == "--":
confTok(L, tok) # skip unnecessary prefix
confTok(L, tok, config) # skip unnecessary prefix
var info = getLineInfo(L, tok) # save for later in case of an error
checkSymbol(L, tok)
var s = tokToStr(tok)
confTok(L, tok) # skip symbol
confTok(L, tok, config) # skip symbol
var val = ""
while tok.tokType == tkDot:
add(s, '.')
confTok(L, tok)
confTok(L, tok, config)
checkSymbol(L, tok)
add(s, tokToStr(tok))
confTok(L, tok)
confTok(L, tok, config)
if tok.tokType == tkBracketLe:
# BUGFIX: val, not s!
# BUGFIX: do not copy '['!
confTok(L, tok)
confTok(L, tok, config)
checkSymbol(L, tok)
add(val, tokToStr(tok))
confTok(L, tok)
if tok.tokType == tkBracketRi: confTok(L, tok)
confTok(L, tok, config)
if tok.tokType == tkBracketRi: confTok(L, tok, config)
else: lexMessage(L, errTokenExpected, "']'")
add(val, ']')
let percent = tok.ident != nil and tok.ident.s == "%="
if tok.tokType in {tkColon, tkEquals} or percent:
if len(val) > 0: add(val, ':')
confTok(L, tok) # skip ':' or '=' or '%'
confTok(L, tok, config) # skip ':' or '=' or '%'
checkSymbol(L, tok)
add(val, tokToStr(tok))
confTok(L, tok) # skip symbol
confTok(L, tok, config) # skip symbol
while tok.ident != nil and tok.ident.s == "&":
confTok(L, tok)
confTok(L, tok, config)
checkSymbol(L, tok)
add(val, tokToStr(tok))
confTok(L, tok)
confTok(L, tok, config)
if percent:
processSwitch(s, strtabs.`%`(val, options.gConfigVars,
{useEnvironment, useEmpty}), passPP, info)
{useEnvironment, useEmpty}), passPP, info, config)
else:
processSwitch(s, val, passPP, info)
processSwitch(s, val, passPP, info, config)
proc readConfigFile(filename: string; cache: IdentCache) =
proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) =
var
L: TLexer
tok: TToken
@ -207,8 +207,8 @@ proc readConfigFile(filename: string; cache: IdentCache) =
initToken(tok)
openLexer(L, filename, stream, cache)
tok.tokType = tkEof # to avoid a pointless warning
confTok(L, tok) # read in the first token
while tok.tokType != tkEof: parseAssignment(L, tok)
confTok(L, tok, config) # read in the first token
while tok.tokType != tkEof: parseAssignment(L, tok, config)
if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end")
closeLexer(L)
rawMessage(hintConf, filename)
@ -225,22 +225,22 @@ proc getSystemConfigPath(filename: string): string =
if not existsFile(result): result = joinPath([p, "etc", filename])
if not existsFile(result): result = "/etc/" & filename
proc loadConfigs*(cfg: string; cache: IdentCache) =
proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) =
setDefaultLibpath()
if optSkipConfigFile notin gGlobalOptions:
readConfigFile(getSystemConfigPath(cfg), cache)
readConfigFile(getSystemConfigPath(cfg), cache, config)
if optSkipUserConfigFile notin gGlobalOptions:
readConfigFile(getUserConfigPath(cfg), cache)
readConfigFile(getUserConfigPath(cfg), cache, config)
var pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir()
if optSkipParentConfigFiles notin gGlobalOptions:
for dir in parentDirs(pd, fromRoot=true, inclusive=false):
readConfigFile(dir / cfg, cache)
readConfigFile(dir / cfg, cache, config)
if optSkipProjConfigFile notin gGlobalOptions:
readConfigFile(pd / cfg, cache)
readConfigFile(pd / cfg, cache, config)
if gProjectName.len != 0:
# new project wide config file:
@ -251,8 +251,8 @@ proc loadConfigs*(cfg: string; cache: IdentCache) =
projectConfig = changeFileExt(gProjectFull, "nimrod.cfg")
if fileExists(projectConfig):
rawMessage(warnDeprecated, projectConfig)
readConfigFile(projectConfig, cache)
readConfigFile(projectConfig, cache, config)
proc loadConfigs*(cfg: string) =
proc loadConfigs*(cfg: string; config: ConfigRef = nil) =
# for backwards compatibility only.
loadConfigs(cfg, newIdentCache())
loadConfigs(cfg, newIdentCache(), config)

View file

@ -102,6 +102,17 @@ type
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod,
ideHighlight, ideOutline
ConfigRef* = ref object ## eventually all global configuration should be moved here
cppDefines*: HashSet[string]
headerFile*: string
proc newConfigRef*(): ConfigRef =
result = ConfigRef(cppDefines: initSet[string](),
headerFile: "")
proc cppDefine*(c: ConfigRef; define: string) =
c.cppDefines.incl define
var
gIdeCmd*: IdeCmd
@ -122,7 +133,7 @@ var
outFile*: string = ""
docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \
# The string uses the formatting variables `path` and `line`.
headerFile*: string = ""
#headerFile*: string = ""
gVerbosity* = 1 # how verbose the compiler is
gNumberOfProcessors*: int # number of processors
gWholeProject*: bool # for 'doc2': output any dependency

View file

@ -665,9 +665,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wExportc:
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
incl(sym.flags, sfUsed) # avoid wrong hints
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"), it.info)
of wImportc:
let name = getOptionalStr(c, it, "$1")
cppDefine(c.graph.config, name)
makeExternImport(sym, name, it.info)
of wImportCompilerProc:
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"), it.info)
let name = getOptionalStr(c, it, "$1")
cppDefine(c.graph.config, name)
processImportCompilerProc(sym, name, it.info)
of wExtern: setExternName(sym, expectStrLit(c, it), it.info)
of wImmediate:
if sym.kind in {skTemplate, skMacro}:
@ -758,6 +763,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
processDynLib(c, it, sym)
of wCompilerproc:
noVal(it) # compilerproc may not get a string!
cppDefine(c.graph.config, sym.name.s)
if sfFromGeneric notin sym.flags: markCompilerProc(sym)
of wProcVar:
noVal(it)

View file

@ -25,7 +25,8 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) =
if kind in filter: result.add path
setResult(a, result)
proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext =
proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
config: ConfigRef = nil): PEvalContext =
# For Nimble we need to export 'setupVM'.
result = newCtx(module, cache)
result.mode = emRepl
@ -109,10 +110,13 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext
let arg = a.getString 1
if arg.len > 0:
gProjectName = arg
let path =
if gProjectName.isAbsolute: gProjectName
else: gProjectPath / gProjectName
try:
gProjectFull = canonicalizePath(gProjectPath / gProjectName)
gProjectFull = canonicalizePath(path)
except OSError:
gProjectFull = gProjectName
gProjectFull = path
cbconf getCommand:
setResult(a, options.command)
cbconf switch:
@ -133,12 +137,15 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext
gModuleOverrides[key] = val
cbconf selfExe:
setResult(a, os.getAppFilename())
cbconf cppDefine:
if config != nil:
options.cppDefine(config, a.getString(0))
proc runNimScript*(cache: IdentCache; scriptName: string;
freshDefines=true) =
freshDefines=true; config: ConfigRef=nil) =
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
let graph = newModuleGraph()
let graph = newModuleGraph(config)
if freshDefines: initDefines()
defineSymbol("nimscript")
@ -150,7 +157,7 @@ proc runNimScript*(cache: IdentCache; scriptName: string;
var m = graph.makeModule(scriptName)
incl(m.flags, sfMainModule)
vm.globalCtx = setupVM(m, cache, scriptName)
vm.globalCtx = setupVM(m, cache, scriptName, config)
graph.compileSystemModule(cache)
discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache)

View file

@ -1052,6 +1052,8 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
# work without now. template/tsymchoicefield doesn't like an early exit
# here at all!
#if isSymChoice(n.sons[1]): return
when defined(nimsuggest):
if gCmd == cmdIdeTools: suggestExpr(c, n)
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule})
if s != nil:

View file

@ -97,10 +97,17 @@ proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
if inst.compilesId == id and sameInstantiation(entry, inst[]):
return inst.sym
when false:
proc `$`(x: PSym): string =
result = x.name.s & " " & " id " & $x.id
proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
# we need to create a fresh set of gensym'ed symbols:
if n.kind == nkSym and sfGenSym in n.sym.flags and
(n.sym.owner == orig or n.sym.owner.kind == skPackage):
#if n.kind == nkSym and sfGenSym in n.sym.flags:
# if n.sym.owner != orig:
# echo "symbol ", n.sym.name.s, " orig ", orig, " owner ", n.sym.owner
if n.kind == nkSym and {sfGenSym, sfFromGeneric} * n.sym.flags == {sfGenSym}: # and
# (n.sym.owner == orig or n.sym.owner.kind in {skPackage}):
let s = n.sym
var x = PSym(idTableGet(symMap, s))
if x == nil:

View file

@ -112,6 +112,7 @@ type
toBind, toMixin, toInject: IntSet
owner: PSym
cursorInBody: bool # only for nimsuggest
scopeN: int
bracketExpr: PNode
template withBracketExpr(ctx, x, body: untyped) =
@ -141,8 +142,13 @@ proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} =
proc semTemplBody(c: var TemplCtx, n: PNode): PNode
proc openScope(c: var TemplCtx) = openScope(c.c)
proc closeScope(c: var TemplCtx) = closeScope(c.c)
proc openScope(c: var TemplCtx) =
openScope(c.c)
inc c.scopeN
proc closeScope(c: var TemplCtx) =
dec c.scopeN
closeScope(c.c)
proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode =
openScope(c)
@ -166,6 +172,7 @@ proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
result = newSym(kind, considerQuotedIdent(n), c.owner, n.info)
incl(result.flags, sfGenSym)
incl(result.flags, sfShadowed)
if c.scopeN == 0: incl(result.flags, sfFromGeneric)
proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
# locals default to 'gensym':

View file

@ -659,7 +659,8 @@ proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
addInheritedFieldsAux(c, check, pos, obj.n)
proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
if n.sonsLen == 0: return newConstraint(c, tyObject)
if n.sonsLen == 0:
return newConstraint(c, tyObject)
var check = initIntSet()
var pos = 0
var base, realBase: PType = nil
@ -1159,8 +1160,16 @@ proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType =
result.sym = prev.sym
assignType(prev, result)
proc fixupTypeOf(c: PContext, prev: PType, typExpr: PNode) =
if prev != nil:
let result = newTypeS(tyAlias, c)
result.rawAddSon typExpr.typ
result.sym = prev.sym
assignType(prev, result)
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil
if gCmd == cmdIdeTools: suggestExpr(c, n)
case n.kind
of nkEmpty: discard
@ -1168,6 +1177,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
checkSonsLen(n, 1)
let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
fixupTypeOf(c, prev, typExpr)
result = typExpr.typ
of nkPar:
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
@ -1234,6 +1244,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
elif op.id == ord(wType):
checkSonsLen(n, 2)
let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
fixupTypeOf(c, prev, typExpr)
result = typExpr.typ
else:
result = semTypeExpr(c, n, prev)

View file

@ -41,6 +41,20 @@ var
template origModuleName(m: PSym): string = m.name.s
proc findDocComment(n: PNode): PNode =
if n == nil: return nil
if not isNil(n.comment): return n
for i in countup(0, safeLen(n)-1):
result = findDocComment(n.sons[i])
if result != nil: return
proc extractDocComment(s: PSym): string =
let n = findDocComment(s.ast)
if not n.isNil:
result = n.comment.replace("\n##", "\n").strip
else:
result = ""
proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo;
quality: range[0..100]): Suggest =
result.section = parseIdeCmd(section)

View file

@ -559,7 +559,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[rb].node.kind == nkRefTy:
regs[ra].node = regs[rb].node.sons[0]
else:
stackTrace(c, tos, pc, errGenerated, "limited VM support for pointers")
ensureKind(rkNode)
regs[ra].node = regs[rb].node
else:
stackTrace(c, tos, pc, errNilAccess)
of opcWrDeref:
@ -932,7 +933,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
c.module
var macroCall = newNodeI(nkCall, c.debug[pc])
macroCall.add(newSymNode(prc))
for i in 1 .. rc-1: macroCall.add(regs[rb+i].regToNode)
for i in 1 .. rc-1:
let node = regs[rb+i].regToNode
node.info = c.debug[pc]
macroCall.add(node)
let a = evalTemplate(macroCall, prc, genSymOwner)
a.recSetFlagIsRef
ensureKind(rkNode)

View file

@ -1259,6 +1259,13 @@ proc isTemp(c: PCtx; dest: TDest): bool =
template needsAdditionalCopy(n): untyped =
not c.isTemp(dest) and not fitsRegister(n.typ)
proc genAdditionalCopy(c: PCtx; n: PNode; opc: TOpcode;
dest, idx, value: TRegister) =
var cc = c.getTemp(n.typ)
c.gABC(n, whichAsgnOpc(n), cc, value, 0)
c.gABC(n, opc, dest, idx, cc)
c.freeTemp(cc)
proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
dest, idx, value: TRegister) =
# opcLdObj et al really means "load address". We sometimes have to create a
@ -1266,10 +1273,7 @@ proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
# mylocal = a.b # needs a copy of the data!
assert n.typ != nil
if needsAdditionalCopy(n):
var cc = c.getTemp(n.typ)
c.gABC(n, whichAsgnOpc(n), cc, value, 0)
c.gABC(n, opc, dest, idx, cc)
c.freeTemp(cc)
genAdditionalCopy(c, n, opc, dest, idx, value)
else:
c.gABC(n, opc, dest, idx, value)
@ -1352,7 +1356,7 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
c.gABx(n, opcLdGlobal, dest, s.position)
if s.ast != nil:
let tmp = c.genx(s.ast)
c.preventFalseAlias(n, opcWrDeref, dest, 0, tmp)
c.genAdditionalCopy(n, opcWrDeref, dest, 0, tmp)
c.freeTemp(dest)
c.freeTemp(tmp)
@ -1506,7 +1510,7 @@ proc genVarSection(c: PCtx; n: PNode) =
#assert(a.sons[0].kind == nkSym) can happen for transformed vars
if a.kind == nkVarTuple:
for i in 0 .. a.len-3:
setSlot(c, a[i].sym)
if not a[i].sym.isGlobal: setSlot(c, a[i].sym)
checkCanEval(c, a[i])
c.gen(lowerTupleUnpacking(a, c.getOwner))
elif a.sons[0].kind == nkSym:
@ -1525,7 +1529,7 @@ proc genVarSection(c: PCtx; n: PNode) =
if a.sons[2].kind != nkEmpty:
let tmp = c.genx(a.sons[0], {gfAddrOf})
let val = c.genx(a.sons[2])
c.preventFalseAlias(a.sons[2], opcWrDeref, tmp, 0, val)
c.genAdditionalCopy(a.sons[2], opcWrDeref, tmp, 0, val)
c.freeTemp(val)
c.freeTemp(tmp)
else: