no ropes WIP (#20433)

* refactorings in preparation for ropes elimination of the C code generator; mostly the usual ': Rope' -> 'result: var Rope' rewrite
* rewrote ccgcalls.nim
* refactored ccgexprs.nim
* ccgliterals: refactoring
* refactoring: code dealing with name mangling
* refactoring: getRecordFieldsAux
* ropes are strings (insert obscene joke here)
* optimize JS code gen
* optimizations and code improvements
* more optimizations
* final cleanups
This commit is contained in:
Andreas Rumpf 2022-09-27 10:57:47 +02:00 • committed by GitHub
commit ca1f3f36b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1058 additions and 1002 deletions

View file

@ -745,7 +745,7 @@ const
mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet,
mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInSet, mRepr, mOpenArrayToSeq} mInSet, mRepr, mOpenArrayToSeq}
generatedMagics* = {mNone, mIsolate, mFinished, mOpenArrayToSeq} generatedMagics* = {mNone, mIsolate, mFinished, mOpenArrayToSeq}
## magics that are generated as normal procs in the backend ## magics that are generated as normal procs in the backend
@ -1504,7 +1504,7 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
if a.storage == low(typeof(a.storage)): a.storage = b.storage if a.storage == low(typeof(a.storage)): a.storage = b.storage
a.flags.incl b.flags a.flags.incl b.flags
if a.lode == nil: a.lode = b.lode if a.lode == nil: a.lode = b.lode
if a.r == nil: a.r = b.r if a.r == "": a.r = b.r
proc newSons*(father: Indexable, length: int) = proc newSons*(father: Indexable, length: int) =
setLen(father.sons, length) setLen(father.sons, length)

View file

@ -12,9 +12,11 @@
# the data structures here are used in various places of the compiler. # the data structures here are used in various places of the compiler.
import import
ast, hashes, intsets, strutils, options, lineinfos, ropes, idents, rodutils, ast, hashes, intsets, options, lineinfos, ropes, idents, rodutils,
msgs msgs
import strutils except addf
when defined(nimPreviewSlimSystem): when defined(nimPreviewSlimSystem):
import std/assertions import std/assertions
@ -258,7 +260,7 @@ proc makeYamlString*(s: string): Rope =
# this could trigger InternalError(111). See the ropes module for # this could trigger InternalError(111). See the ropes module for
# further information. # further information.
const MaxLineLength = 64 const MaxLineLength = 64
result = nil result = ""
var res = "\"" var res = "\""
for i in 0..<s.len: for i in 0..<s.len:
if (i + 1) mod MaxLineLength == 0: if (i + 1) mod MaxLineLength == 0:
@ -274,9 +276,9 @@ proc flagsToStr[T](flags: set[T]): Rope =
if flags == {}: if flags == {}:
result = rope("[]") result = rope("[]")
else: else:
result = nil result = ""
for x in items(flags): for x in items(flags):
if result != nil: result.add(", ") if result != "": result.add(", ")
result.add(makeYamlString($x)) result.add(makeYamlString($x))
result = "[" & result & "]" result = "[" & result & "]"

View file

@ -77,12 +77,12 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
callee, params: Rope) = callee, params: Rope) =
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0]) let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
genLineDir(p, ri) genLineDir(p, ri)
var pl = callee & ~"(" & params var pl = callee & "(" & params
# getUniqueType() is too expensive here: # getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst) var typ = skipTypes(ri[0].typ, abstractInst)
if typ[0] != nil: if typ[0] != nil:
if isInvalidReturnType(p.config, typ): if isInvalidReturnType(p.config, typ):
if params != nil: pl.add(~", ") if params.len != 0: pl.add(", ")
# beware of 'result = p(result)'. We may need to allocate a temporary: # beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri): if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd': # Great, we can use 'd':
@ -91,18 +91,18 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
# reset before pass as 'result' var: # reset before pass as 'result' var:
discard "resetLoc(p, d)" discard "resetLoc(p, d)"
pl.add(addrLoc(p.config, d)) pl.add(addrLoc(p.config, d))
pl.add(~");$n") pl.add(");\n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true) getTemp(p, typ[0], tmp, needsInit=true)
pl.add(addrLoc(p.config, tmp)) pl.add(addrLoc(p.config, tmp))
pl.add(~");$n") pl.add(");\n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
if canRaise: raiseExit(p) if canRaise: raiseExit(p)
else: else:
pl.add(~")") pl.add(")")
if p.module.compileToCpp: if p.module.compileToCpp:
if lfSingleUse in d.flags: if lfSingleUse in d.flags:
# do not generate spurious temporaries for C++! For C we're better off # do not generate spurious temporaries for C++! For C we're better off
@ -140,7 +140,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
if canRaise: raiseExit(p) if canRaise: raiseExit(p)
genAssignment(p, d, tmp, {}) genAssignment(p, d, tmp, {})
else: else:
pl.add(~");$n") pl.add(");\n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
if canRaise: raiseExit(p) if canRaise: raiseExit(p)
@ -173,8 +173,10 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope,
result = ("($3*)(($1)+($2))" % [rdLoc(a), rdLoc(b), dest], result = ("($3*)(($1)+($2))" % [rdLoc(a), rdLoc(b), dest],
lengthExpr) lengthExpr)
else: else:
var lit = newRopeAppender()
intLiteral(first, lit)
result = ("($4*)($1)+(($2)-($3))" % result = ("($4*)($1)+(($2)-($3))" %
[rdLoc(a), rdLoc(b), intLiteral(first), dest], [rdLoc(a), rdLoc(b), lit, dest],
lengthExpr) lengthExpr)
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
if reifiedOpenArray(q[1]): if reifiedOpenArray(q[1]):
@ -200,7 +202,7 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope,
else: else:
internalError(p.config, "openArrayLoc: " & typeToString(a.t)) internalError(p.config, "openArrayLoc: " & typeToString(a.t))
proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
var q = skipConv(n) var q = skipConv(n)
var skipped = false var skipped = false
while q.kind == nkStmtListExpr and q.len > 0: while q.kind == nkStmtListExpr and q.len > 0:
@ -215,7 +217,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
genStmts(p, q[i]) genStmts(p, q[i])
q = q.lastSon q = q.lastSon
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0]) let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0])
result = x & ", " & y result.add x & ", " & y
else: else:
var a: TLoc var a: TLoc
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a) initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
@ -223,11 +225,11 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
if reifiedOpenArray(n): if reifiedOpenArray(n):
if a.t.kind in {tyVar, tyLent}: if a.t.kind in {tyVar, tyLent}:
result = "$1->Field0, $1->Field1" % [rdLoc(a)] result.add "$1->Field0, $1->Field1" % [rdLoc(a)]
else: else:
result = "$1.Field0, $1.Field1" % [rdLoc(a)] result.add "$1.Field0, $1.Field1" % [rdLoc(a)]
else: else:
result = "$1, $1Len_0" % [rdLoc(a)] result.add "$1, $1Len_0" % [rdLoc(a)]
of tyString, tySequence: of tyString, tySequence:
let ntyp = skipTypes(n.typ, abstractInst) let ntyp = skipTypes(n.typ, abstractInst)
if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and
@ -236,19 +238,19 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
if ntyp.kind in {tyVar} and not compileToCpp(p.module): if ntyp.kind in {tyVar} and not compileToCpp(p.module):
var t: TLoc var t: TLoc
t.r = "(*$1)" % [a.rdLoc] t.r = "(*$1)" % [a.rdLoc]
result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)] result.add "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
else: else:
result = "$1$3, $2" % [a.rdLoc, lenExpr(p, a), dataField(p)] result.add "$1$3, $2" % [a.rdLoc, lenExpr(p, a), dataField(p)]
of tyArray: of tyArray:
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))] result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))]
of tyPtr, tyRef: of tyPtr, tyRef:
case lastSon(a.t).kind case lastSon(a.t).kind
of tyString, tySequence: of tyString, tySequence:
var t: TLoc var t: TLoc
t.r = "(*$1)" % [a.rdLoc] t.r = "(*$1)" % [a.rdLoc]
result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)] result.add "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
of tyArray: of tyArray:
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))] result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))]
else: else:
internalError(p.config, "openArrayLoc: " & typeToString(a.t)) internalError(p.config, "openArrayLoc: " & typeToString(a.t))
else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) else: internalError(p.config, "openArrayLoc: " & typeToString(a.t))
@ -268,24 +270,24 @@ proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc =
getTemp(p, a.lode.typ, result, needsInit=false) getTemp(p, a.lode.typ, result, needsInit=false)
genAssignment(p, result, a, {}) genAssignment(p, result, a, {})
proc genArgStringToCString(p: BProc, n: PNode, needsTmp: bool): Rope {.inline.} = proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} =
var a: TLoc var a: TLoc
initLocExpr(p, n[0], a) initLocExpr(p, n[0], a)
ropecg(p.module, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc]) appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc])
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode, needsTmp = false): Rope = proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) =
var a: TLoc var a: TLoc
if n.kind == nkStringToCString: if n.kind == nkStringToCString:
result = genArgStringToCString(p, n, needsTmp) genArgStringToCString(p, n, result, needsTmp)
elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
var n = if n.kind != nkHiddenAddr: n else: n[0] var n = if n.kind != nkHiddenAddr: n else: n[0]
result = openArrayLoc(p, param.typ, n) openArrayLoc(p, param.typ, n, result)
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]): elif ccgIntroducedPtr(p.config, param, call[0].typ[0]):
initLocExpr(p, n, a) initLocExpr(p, n, a)
if n.kind in {nkCharLit..nkNilLit}: if n.kind in {nkCharLit..nkNilLit}:
result = addrLoc(p.config, literalsNeedsTmp(p, a)) addAddrLoc(p.config, literalsNeedsTmp(p, a), result)
else: else:
result = addrLoc(p.config, withTmpIfNeeded(p, a, needsTmp)) addAddrLoc(p.config, withTmpIfNeeded(p, a, needsTmp), result)
elif p.module.compileToCpp and param.typ.kind in {tyVar} and elif p.module.compileToCpp and param.typ.kind in {tyVar} and
n.kind == nkHiddenAddr: n.kind == nkHiddenAddr:
initLocExprSingleUse(p, n[0], a) initLocExprSingleUse(p, n[0], a)
@ -295,21 +297,21 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode, needsTmp = false): Rop
if callee.kind == nkSym and if callee.kind == nkSym and
{sfImportc, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportc} and {sfImportc, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportc} and
{lfHeader, lfNoDecl} * callee.sym.loc.flags != {}: {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
result = addrLoc(p.config, a) addAddrLoc(p.config, a, result)
else: else:
result = rdLoc(a) addRdLoc(a, result)
else: else:
initLocExprSingleUse(p, n, a) initLocExprSingleUse(p, n, a)
result = rdLoc(withTmpIfNeeded(p, a, needsTmp)) addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
#assert result != nil #assert result != nil
proc genArgNoParam(p: BProc, n: PNode, needsTmp = false): Rope = proc genArgNoParam(p: BProc, n: PNode; result: var Rope; needsTmp = false) =
var a: TLoc var a: TLoc
if n.kind == nkStringToCString: if n.kind == nkStringToCString:
result = genArgStringToCString(p, n, needsTmp) genArgStringToCString(p, n, result, needsTmp)
else: else:
initLocExprSingleUse(p, n, a) initLocExprSingleUse(p, n, a)
result = rdLoc(withTmpIfNeeded(p, a, needsTmp)) addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
from dfa import aliases, AliasKind from dfa import aliases, AliasKind
@ -365,7 +367,7 @@ proc getPotentialReads(n: PNode; result: var seq[PNode]) =
for s in n: for s in n:
getPotentialReads(s, result) getPotentialReads(s, result)
proc genParams(p: BProc, ri: PNode, typ: PType): Rope = proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
# We must generate temporaries in cases like #14396 # We must generate temporaries in cases like #14396
# to keep the strict Left-To-Right evaluation # to keep the strict Left-To-Right evaluation
var needTmp = newSeq[bool](ri.len - 1) var needTmp = newSeq[bool](ri.len - 1)
@ -385,16 +387,21 @@ proc genParams(p: BProc, ri: PNode, typ: PType): Rope =
# Optimization: don't use a temp, if we would only take the address anyway # Optimization: don't use a temp, if we would only take the address anyway
needTmp[i - 1] = false needTmp[i - 1] = false
var oldLen = result.len
for i in 1..<ri.len: for i in 1..<ri.len:
if i < typ.len: if i < typ.len:
assert(typ.n[i].kind == nkSym) assert(typ.n[i].kind == nkSym)
let paramType = typ.n[i] let paramType = typ.n[i]
if not paramType.typ.isCompileTimeOnly: if not paramType.typ.isCompileTimeOnly:
if result != nil: result.add(~", ") if oldLen != result.len:
result.add(genArg(p, ri[i], paramType.sym, ri, needTmp[i-1])) result.add(", ")
oldLen = result.len
genArg(p, ri[i], paramType.sym, ri, result, needTmp[i-1])
else: else:
if result != nil: result.add(~", ") if oldLen != result.len:
result.add(genArgNoParam(p, ri[i], needTmp[i-1])) result.add(", ")
oldLen = result.len
genArgNoParam(p, ri[i], result, needTmp[i-1])
proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) = proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
if sym.flags * {sfImportc, sfNonReloadable} == {} and sym.loc.k == locProc and if sym.flags * {sfImportc, sfNonReloadable} == {} and sym.loc.k == locProc and
@ -410,7 +417,8 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
assert(typ.len == typ.n.len) assert(typ.len == typ.n.len)
var params = genParams(p, ri, typ) var params = newRopeAppender()
genParams(p, ri, typ, params)
var callee = rdLoc(op) var callee = rdLoc(op)
if p.hcrOn and ri[0].kind == nkSym: if p.hcrOn and ri[0].kind == nkSym:
@ -420,7 +428,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc addComma(r: Rope): Rope = proc addComma(r: Rope): Rope =
if r == nil: r else: r & ~", " if r.len == 0: r else: r & ", "
const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)" const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)"
const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists
@ -433,7 +441,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
assert(typ.len == typ.n.len) assert(typ.len == typ.n.len)
var pl = genParams(p, ri, typ) var pl = newRopeAppender()
genParams(p, ri, typ, pl)
template genCallPattern {.dirty.} = template genCallPattern {.dirty.} =
if tfIterator in typ.flags: if tfIterator in typ.flags:
@ -445,7 +454,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0]) let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
if typ[0] != nil: if typ[0] != nil:
if isInvalidReturnType(p.config, typ): if isInvalidReturnType(p.config, typ):
if ri.len > 1: pl.add(~", ") if ri.len > 1: pl.add(", ")
# beware of 'result = p(result)'. We may need to allocate a temporary: # beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri): if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd': # Great, we can use 'd':
@ -491,24 +500,30 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genCallPattern() genCallPattern()
if canRaise: raiseExit(p) if canRaise: raiseExit(p)
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope;
argsCounter: var int) =
if i < typ.len: if i < typ.len:
# 'var T' is 'T&' in C++. This means we ignore the request of # 'var T' is 'T&' in C++. This means we ignore the request of
# any nkHiddenAddr when it's a 'var T'. # any nkHiddenAddr when it's a 'var T'.
let paramType = typ.n[i] let paramType = typ.n[i]
assert(paramType.kind == nkSym) assert(paramType.kind == nkSym)
if paramType.typ.isCompileTimeOnly: if paramType.typ.isCompileTimeOnly:
result = nil discard
elif typ[i].kind in {tyVar} and ri[i].kind == nkHiddenAddr: elif typ[i].kind in {tyVar} and ri[i].kind == nkHiddenAddr:
result = genArgNoParam(p, ri[i][0]) if argsCounter > 0: result.add ", "
genArgNoParam(p, ri[i][0], result)
inc argsCounter
else: else:
result = genArgNoParam(p, ri[i]) #, typ.n[i].sym) if argsCounter > 0: result.add ", "
genArgNoParam(p, ri[i], result) #, typ.n[i].sym)
inc argsCounter
else: else:
if tfVarargs notin typ.flags: if tfVarargs notin typ.flags:
localError(p.config, ri.info, "wrong argument count") localError(p.config, ri.info, "wrong argument count")
result = nil
else: else:
result = genArgNoParam(p, ri[i]) if argsCounter > 0: result.add ", "
genArgNoParam(p, ri[i], result)
inc argsCounter
discard """ discard """
Dot call syntax in C++ Dot call syntax in C++
@ -565,7 +580,7 @@ proc skipAddrDeref(node: PNode): PNode =
else: else:
result = node result = node
proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope) =
# for better or worse c2nim translates the 'this' argument to a 'var T'. # for better or worse c2nim translates the 'this' argument to a 'var T'.
# However manual wrappers may also use 'ptr T'. In any case we support both # However manual wrappers may also use 'ptr T'. In any case we support both
# for convenience. # for convenience.
@ -579,75 +594,72 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
if t.kind in {tyVar}: if t.kind in {tyVar}:
let x = if ri.kind == nkHiddenAddr: ri[0] else: ri let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
if x.typ.kind == tyPtr: if x.typ.kind == tyPtr:
result = genArgNoParam(p, x) genArgNoParam(p, x, result)
result.add("->") result.add("->")
elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr: elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr:
result = genArgNoParam(p, x[0]) genArgNoParam(p, x[0], result)
result.add("->") result.add("->")
else: else:
result = genArgNoParam(p, x) genArgNoParam(p, x, result)
result.add(".") result.add(".")
elif t.kind == tyPtr: elif t.kind == tyPtr:
if ri.kind in {nkAddr, nkHiddenAddr}: if ri.kind in {nkAddr, nkHiddenAddr}:
result = genArgNoParam(p, ri[0]) genArgNoParam(p, ri[0], result)
result.add(".") result.add(".")
else: else:
result = genArgNoParam(p, ri) genArgNoParam(p, ri, result)
result.add("->") result.add("->")
else: else:
ri = skipAddrDeref(ri) ri = skipAddrDeref(ri)
if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0] if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0]
result = genArgNoParam(p, ri) #, typ.n[i].sym) genArgNoParam(p, ri, result) #, typ.n[i].sym)
result.add(".") result.add(".")
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope = proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Rope) =
var i = 0 var i = 0
var j = 1 var j = 1
while i < pat.len: while i < pat.len:
case pat[i] case pat[i]
of '@': of '@':
var first = true var argsCounter = 0
for k in j..<ri.len: for k in j..<ri.len:
let arg = genOtherArg(p, ri, k, typ) genOtherArg(p, ri, k, typ, result, argsCounter)
if arg.len > 0:
if not first:
result.add(~", ")
first = false
result.add arg
inc i inc i
of '#': of '#':
if i+1 < pat.len and pat[i+1] in {'+', '@'}: if i+1 < pat.len and pat[i+1] in {'+', '@'}:
let ri = ri[j] let ri = ri[j]
if ri.kind in nkCallKinds: if ri.kind in nkCallKinds:
let typ = skipTypes(ri[0].typ, abstractInst) let typ = skipTypes(ri[0].typ, abstractInst)
if pat[i+1] == '+': result.add genArgNoParam(p, ri[0]) if pat[i+1] == '+': genArgNoParam(p, ri[0], result)
result.add(~"(") result.add("(")
if 1 < ri.len: if 1 < ri.len:
result.add genOtherArg(p, ri, 1, typ) var argsCounterB = 0
genOtherArg(p, ri, 1, typ, result, argsCounterB)
for k in j+1..<ri.len: for k in j+1..<ri.len:
result.add(~", ") var argsCounterB = 0
result.add genOtherArg(p, ri, k, typ) genOtherArg(p, ri, k, typ, result, argsCounterB)
result.add(~")") result.add(")")
else: else:
localError(p.config, ri.info, "call expression expected for C++ pattern") localError(p.config, ri.info, "call expression expected for C++ pattern")
inc i inc i
elif i+1 < pat.len and pat[i+1] == '.': elif i+1 < pat.len and pat[i+1] == '.':
result.add genThisArg(p, ri, j, typ) genThisArg(p, ri, j, typ, result)
inc i inc i
elif i+1 < pat.len and pat[i+1] == '[': elif i+1 < pat.len and pat[i+1] == '[':
var arg = ri[j].skipAddrDeref var arg = ri[j].skipAddrDeref
while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0] while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0]
result.add genArgNoParam(p, arg) genArgNoParam(p, arg, result)
#result.add debugTree(arg, 0, 10) #result.add debugTree(arg, 0, 10)
else: else:
result.add genOtherArg(p, ri, j, typ) var argsCounter = 0
genOtherArg(p, ri, j, typ, result, argsCounter)
inc j inc j
inc i inc i
of '\'': of '\'':
var idx, stars: int var idx, stars: int
if scanCppGenericSlot(pat, i, idx, stars): if scanCppGenericSlot(pat, i, idx, stars):
var t = resolveStarsInCppType(typ, idx, stars) var t = resolveStarsInCppType(typ, idx, stars)
if t == nil: result.add(~"void") if t == nil: result.add("void")
else: result.add(getTypeDesc(p.module, t)) else: result.add(getTypeDesc(p.module, t))
else: else:
let start = i let start = i
@ -665,10 +677,11 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
assert(typ.len == typ.n.len) assert(typ.len == typ.n.len)
# don't call '$' here for efficiency: # don't call '$' here for efficiency:
let pat = ri[0].sym.loc.r.data let pat = $ri[0].sym.loc.r
internalAssert p.config, pat.len > 0 internalAssert p.config, pat.len > 0
if pat.contains({'#', '(', '@', '\''}): if pat.contains({'#', '(', '@', '\''}):
var pl = genPatternCall(p, ri, pat, typ) var pl = newRopeAppender()
genPatternCall(p, ri, pat, typ, pl)
# simpler version of 'fixupCall' that works with the pl+params combination: # simpler version of 'fixupCall' that works with the pl+params combination:
var typ = skipTypes(ri[0].typ, abstractInst) var typ = skipTypes(ri[0].typ, abstractInst)
if typ[0] != nil: if typ[0] != nil:
@ -687,80 +700,79 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
list.r = pl list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying genAssignment(p, d, list, {}) # no need for deep copying
else: else:
pl.add(~";$n") pl.add(";\n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
else: else:
var pl: Rope = nil var pl = newRopeAppender()
#var param = typ.n[1].sym var argsCounter = 0
if 1 < ri.len: if 1 < ri.len:
pl.add(genThisArg(p, ri, 1, typ)) genThisArg(p, ri, 1, typ, pl)
pl.add(op.r) pl.add(op.r)
var params: Rope var params = newRopeAppender()
for i in 2..<ri.len: for i in 2..<ri.len:
if params != nil: params.add(~", ")
assert(typ.len == typ.n.len) assert(typ.len == typ.n.len)
params.add(genOtherArg(p, ri, i, typ)) genOtherArg(p, ri, i, typ, params, argsCounter)
fixupCall(p, le, ri, d, pl, params) fixupCall(p, le, ri, d, pl, params)
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# generates a crappy ObjC call # generates a crappy ObjC call
var op: TLoc var op: TLoc
initLocExpr(p, ri[0], op) initLocExpr(p, ri[0], op)
var pl = ~"[" var pl = "["
# getUniqueType() is too expensive here: # getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst) var typ = skipTypes(ri[0].typ, abstractInst)
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
assert(typ.len == typ.n.len) assert(typ.len == typ.n.len)
# don't call '$' here for efficiency: # don't call '$' here for efficiency:
let pat = ri[0].sym.loc.r.data let pat = $ri[0].sym.loc.r
internalAssert p.config, pat.len > 0 internalAssert p.config, pat.len > 0
var start = 3 var start = 3
if ' ' in pat: if ' ' in pat:
start = 1 start = 1
pl.add(op.r) pl.add(op.r)
if ri.len > 1: if ri.len > 1:
pl.add(~": ") pl.add(": ")
pl.add(genArg(p, ri[1], typ.n[1].sym, ri)) genArg(p, ri[1], typ.n[1].sym, ri, pl)
start = 2 start = 2
else: else:
if ri.len > 1: if ri.len > 1:
pl.add(genArg(p, ri[1], typ.n[1].sym, ri)) genArg(p, ri[1], typ.n[1].sym, ri, pl)
pl.add(~" ") pl.add(" ")
pl.add(op.r) pl.add(op.r)
if ri.len > 2: if ri.len > 2:
pl.add(~": ") pl.add(": ")
pl.add(genArg(p, ri[2], typ.n[2].sym, ri)) genArg(p, ri[2], typ.n[2].sym, ri, pl)
for i in start..<ri.len: for i in start..<ri.len:
assert(typ.len == typ.n.len) assert(typ.len == typ.n.len)
if i >= typ.len: if i >= typ.len:
internalError(p.config, ri.info, "varargs for objective C method?") internalError(p.config, ri.info, "varargs for objective C method?")
assert(typ.n[i].kind == nkSym) assert(typ.n[i].kind == nkSym)
var param = typ.n[i].sym var param = typ.n[i].sym
pl.add(~" ") pl.add(" ")
pl.add(param.name.s) pl.add(param.name.s)
pl.add(~": ") pl.add(": ")
pl.add(genArg(p, ri[i], param, ri)) genArg(p, ri[i], param, ri, pl)
if typ[0] != nil: if typ[0] != nil:
if isInvalidReturnType(p.config, typ): if isInvalidReturnType(p.config, typ):
if ri.len > 1: pl.add(~" ") if ri.len > 1: pl.add(" ")
# beware of 'result = p(result)'. We always allocate a temporary: # beware of 'result = p(result)'. We always allocate a temporary:
if d.k in {locTemp, locNone}: if d.k in {locTemp, locNone}:
# We already got a temp. Great, special case it: # We already got a temp. Great, special case it:
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true) if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
pl.add(~"Result: ") pl.add("Result: ")
pl.add(addrLoc(p.config, d)) pl.add(addrLoc(p.config, d))
pl.add(~"];$n") pl.add("];\n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true) getTemp(p, typ[0], tmp, needsInit=true)
pl.add(addrLoc(p.config, tmp)) pl.add(addrLoc(p.config, tmp))
pl.add(~"];$n") pl.add("];\n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
else: else:
pl.add(~"]") pl.add("]")
if d.k == locNone: getTemp(p, typ[0], d) if d.k == locNone: getTemp(p, typ[0], d)
assert(d.t != nil) # generate an assignment to d: assert(d.t != nil) # generate an assignment to d:
var list: TLoc var list: TLoc
@ -768,7 +780,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
list.r = pl list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying genAssignment(p, d, list, {}) # no need for deep copying
else: else:
pl.add(~"];$n") pl.add("];\n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
proc notYetAlive(n: PNode): bool {.inline.} = proc notYetAlive(n: PNode): bool {.inline.} =

File diff suppressed because it is too large Load diff

View file

@ -32,82 +32,87 @@ proc detectSeqVersion(m: BModule): int =
# ----- Version 1: GC'ed strings and seqs -------------------------------- # ----- Version 1: GC'ed strings and seqs --------------------------------
proc genStringLiteralDataOnlyV1(m: BModule, s: string): Rope = proc genStringLiteralDataOnlyV1(m: BModule, s: string; result: var Rope) =
discard cgsym(m, "TGenericSeq") cgsym(m, "TGenericSeq")
result = getTempName(m) let tmp = getTempName(m)
m.s[cfsData].addf("STRING_LITERAL($1, $2, $3);$n", result.add tmp
[result, makeCString(s), rope(s.len)]) m.s[cfsStrData].addf("STRING_LITERAL($1, $2, $3);$n",
[tmp, makeCString(s), rope(s.len)])
proc genStringLiteralV1(m: BModule; n: PNode): Rope = proc genStringLiteralV1(m: BModule; n: PNode; result: var Rope) =
if s.isNil: if s.isNil:
result = ropecg(m, "((#NimStringDesc*) NIM_NIL)", []) appcg(m, result, "((#NimStringDesc*) NIM_NIL)", [])
else: else:
let id = nodeTableTestOrSet(m.dataCache, n, m.labels) let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
if id == m.labels: if id == m.labels:
# string literal not found in the cache: # string literal not found in the cache:
result = ropecg(m, "((#NimStringDesc*) &$1)", appcg(m, result, "((#NimStringDesc*) &", [])
[genStringLiteralDataOnlyV1(m, n.strVal)]) genStringLiteralDataOnlyV1(m, n.strVal, result)
result.add ")"
else: else:
result = ropecg(m, "((#NimStringDesc*) &$1$2)", appcg(m, result, "((#NimStringDesc*) &$1$2)",
[m.tmpBase, id]) [m.tmpBase, id])
# ------ Version 2: destructor based strings and seqs ----------------------- # ------ Version 2: destructor based strings and seqs -----------------------
proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) = proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) =
m.s[cfsData].addf("static $4 struct {$n" & m.s[cfsStrData].addf("static $4 struct {$n" &
" NI cap; NIM_CHAR data[$2+1];$n" & " NI cap; NIM_CHAR data[$2+1];$n" &
"} $1 = { $2 | NIM_STRLIT_FLAG, $3 };$n", "} $1 = { $2 | NIM_STRLIT_FLAG, $3 };$n",
[result, rope(s.len), makeCString(s), [result, rope(s.len), makeCString(s),
rope(if isConst: "const" else: "")]) rope(if isConst: "const" else: "")])
proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool): Rope = proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Rope) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels) let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
if id == m.labels: if id == m.labels:
let pureLit = getTempName(m) let pureLit = getTempName(m)
genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst) genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst)
result = getTempName(m) let tmp = getTempName(m)
discard cgsym(m, "NimStrPayload") result.add tmp
discard cgsym(m, "NimStringV2") cgsym(m, "NimStrPayload")
cgsym(m, "NimStringV2")
# string literal not found in the cache: # string literal not found in the cache:
m.s[cfsData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n", m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
[result, rope(n.strVal.len), pureLit, rope(if isConst: "const" else: "")]) [tmp, rope(n.strVal.len), pureLit, rope(if isConst: "const" else: "")])
else: else:
result = getTempName(m) let tmp = getTempName(m)
m.s[cfsData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n", result.add tmp
[result, rope(n.strVal.len), m.tmpBase & rope(id), m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
[tmp, rope(n.strVal.len), m.tmpBase & rope(id),
rope(if isConst: "const" else: "")]) rope(if isConst: "const" else: "")])
proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool): Rope = proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Rope) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels) let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var pureLit: Rope var pureLit: Rope
if id == m.labels: if id == m.labels:
pureLit = getTempName(m) pureLit = getTempName(m)
discard cgsym(m, "NimStrPayload") cgsym(m, "NimStrPayload")
discard cgsym(m, "NimStringV2") cgsym(m, "NimStringV2")
# string literal not found in the cache: # string literal not found in the cache:
genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst) genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst)
else: else:
pureLit = m.tmpBase & rope(id) pureLit = m.tmpBase & rope(id)
result = "{$1, (NimStrPayload*)&$2}" % [rope(n.strVal.len), pureLit] result.addf "{$1, (NimStrPayload*)&$2}", [rope(n.strVal.len), pureLit]
# ------ Version selector --------------------------------------------------- # ------ Version selector ---------------------------------------------------
proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo; proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
isConst: bool): Rope = isConst: bool; result: var Rope) =
case detectStrVersion(m) case detectStrVersion(m)
of 0, 1: result = genStringLiteralDataOnlyV1(m, s) of 0, 1: genStringLiteralDataOnlyV1(m, s, result)
of 2: of 2:
result = getTempName(m) let tmp = getTempName(m)
genStringLiteralDataOnlyV2(m, s, result, isConst) genStringLiteralDataOnlyV2(m, s, tmp, isConst)
result.add tmp
else: else:
localError(m.config, info, "cannot determine how to produce code for string literal") localError(m.config, info, "cannot determine how to produce code for string literal")
proc genNilStringLiteral(m: BModule; info: TLineInfo): Rope = proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Rope) =
result = ropecg(m, "((#NimStringDesc*) NIM_NIL)", []) appcg(m, result, "((#NimStringDesc*) NIM_NIL)", [])
proc genStringLiteral(m: BModule; n: PNode): Rope = proc genStringLiteral(m: BModule; n: PNode; result: var Rope) =
case detectStrVersion(m) case detectStrVersion(m)
of 0, 1: result = genStringLiteralV1(m, n) of 0, 1: genStringLiteralV1(m, n, result)
of 2: result = genStringLiteralV2(m, n, isConst = true) of 2: genStringLiteralV2(m, n, isConst = true, result)
else: else:
localError(m.config, n.info, "cannot determine how to produce code for string literal") localError(m.config, n.info, "cannot determine how to produce code for string literal")

View file

@ -24,7 +24,7 @@ proc specializeResetN(p: BProc, accessor: Rope, n: PNode;
of nkRecCase: of nkRecCase:
if (n[0].kind != nkSym): internalError(p.config, n.info, "specializeResetN") if (n[0].kind != nkSym): internalError(p.config, n.info, "specializeResetN")
let disc = n[0].sym let disc = n[0].sym
if disc.loc.r == nil: fillObjectFields(p.module, typ) if disc.loc.r == "": fillObjectFields(p.module, typ)
if disc.loc.t == nil: if disc.loc.t == nil:
internalError(p.config, n.info, "specializeResetN()") internalError(p.config, n.info, "specializeResetN()")
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r]) lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
@ -42,7 +42,7 @@ proc specializeResetN(p: BProc, accessor: Rope, n: PNode;
of nkSym: of nkSym:
let field = n.sym let field = n.sym
if field.typ.kind == tyVoid: return if field.typ.kind == tyVoid: return
if field.loc.r == nil: fillObjectFields(p.module, typ) if field.loc.r == "": fillObjectFields(p.module, typ)
if field.loc.t == nil: if field.loc.t == nil:
internalError(p.config, n.info, "specializeResetN()") internalError(p.config, n.info, "specializeResetN()")
specializeResetT(p, "$1.$2" % [accessor, field.loc.r], field.loc.t) specializeResetT(p, "$1.$2" % [accessor, field.loc.r], field.loc.t)

View file

@ -15,21 +15,22 @@ const
stringCaseThreshold = 8 stringCaseThreshold = 8
# above X strings a hash-switch for strings is generated # above X strings a hash-switch for strings is generated
proc getTraverseProc(p: BProc, v: PSym): Rope = proc registerTraverseProc(p: BProc, v: PSym) =
var traverseProc = ""
if p.config.selectedGC in {gcMarkAndSweep, gcHooks, gcRefc} and if p.config.selectedGC in {gcMarkAndSweep, gcHooks, gcRefc} and
optOwnedRefs notin p.config.globalOptions and optOwnedRefs notin p.config.globalOptions and
containsGarbageCollectedRef(v.loc.t): containsGarbageCollectedRef(v.loc.t):
# we register a specialized marked proc here; this has the advantage # we register a specialized marked proc here; this has the advantage
# that it works out of the box for thread local storage then :-) # that it works out of the box for thread local storage then :-)
result = genTraverseProcForGlobal(p.module, v, v.info) traverseProc = genTraverseProcForGlobal(p.module, v, v.info)
proc registerTraverseProc(p: BProc, v: PSym, traverseProc: Rope) = if traverseProc.len != 0 and not p.hcrOn:
if sfThread in v.flags: if sfThread in v.flags:
appcg(p.module, p.module.preInitProc.procSec(cpsInit), appcg(p.module, p.module.preInitProc.procSec(cpsInit),
"$n\t#nimRegisterThreadLocalMarker($1);$n$n", [traverseProc]) "$n\t#nimRegisterThreadLocalMarker($1);$n$n", [traverseProc])
else: else:
appcg(p.module, p.module.preInitProc.procSec(cpsInit), appcg(p.module, p.module.preInitProc.procSec(cpsInit),
"$n\t#nimRegisterGlobalMarker($1);$n$n", [traverseProc]) "$n\t#nimRegisterGlobalMarker($1);$n$n", [traverseProc])
proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} = proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
if n.kind == nkEmpty: if n.kind == nkEmpty:
@ -54,7 +55,9 @@ proc inExceptBlockLen(p: BProc): int =
proc startBlockInternal(p: BProc): int {.discardable.} = proc startBlockInternal(p: BProc): int {.discardable.} =
inc(p.labels) inc(p.labels)
result = p.blocks.len result = p.blocks.len
setLen(p.blocks, result + 1)
p.blocks.add initBlock()
p.blocks[result].id = p.labels p.blocks[result].id = p.labels
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16 p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
p.blocks[result].nestedExceptStmts = p.inExceptBlockLen.int16 p.blocks[result].nestedExceptStmts = p.inExceptBlockLen.int16
@ -78,7 +81,7 @@ proc genVarTuple(p: BProc, n: PNode) =
# check only the first son # check only the first son
var forHcr = treatGlobalDifferentlyForHCR(p.module, n[0].sym) var forHcr = treatGlobalDifferentlyForHCR(p.module, n[0].sym)
let hcrCond = if forHcr: getTempName(p.module) else: nil let hcrCond = if forHcr: getTempName(p.module) else: ""
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]] var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]]
# determine if the tuple is constructed at top-level scope or inside of a block (if/while/block) # determine if the tuple is constructed at top-level scope or inside of a block (if/while/block)
let isGlobalInBlock = forHcr and p.blocks.len > 2 let isGlobalInBlock = forHcr and p.blocks.len > 2
@ -97,13 +100,10 @@ proc genVarTuple(p: BProc, n: PNode) =
let vn = n[i] let vn = n[i]
let v = vn.sym let v = vn.sym
if sfCompileTime in v.flags: continue if sfCompileTime in v.flags: continue
var traverseProc: Rope
if sfGlobal in v.flags: if sfGlobal in v.flags:
assignGlobalVar(p, vn, nil) assignGlobalVar(p, vn, "")
genObjectInit(p, cpsInit, v.typ, v.loc, constructObj) genObjectInit(p, cpsInit, v.typ, v.loc, constructObj)
traverseProc = getTraverseProc(p, v) registerTraverseProc(p, v)
if traverseProc != nil and not p.hcrOn:
registerTraverseProc(p, v, traverseProc)
else: else:
assignLocalVar(p, vn) assignLocalVar(p, vn)
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1])) initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1]))
@ -115,7 +115,7 @@ proc genVarTuple(p: BProc, n: PNode) =
field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n[i].sym)] field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n[i].sym)]
putLocIntoDest(p, v.loc, field) putLocIntoDest(p, v.loc, field)
if forHcr or isGlobalInBlock: if forHcr or isGlobalInBlock:
hcrGlobals.add((loc: v.loc, tp: if traverseProc == nil: ~"NULL" else: traverseProc)) hcrGlobals.add((loc: v.loc, tp: "NULL"))
if forHcr: if forHcr:
# end the block where the tuple gets initialized # end the block where the tuple gets initialized
@ -145,12 +145,12 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
a.flags.incl(lfEnforceDeref) a.flags.incl(lfEnforceDeref)
expr(p, ri, a) expr(p, ri, a)
proc assignLabel(b: var TBlock): Rope {.inline.} = proc assignLabel(b: var TBlock; result: var Rope) {.inline.} =
b.label = "LA" & b.id.rope b.label = "LA" & b.id.rope
result = b.label result.add b.label
proc blockBody(b: var TBlock): Rope = proc blockBody(b: var TBlock; result: var Rope) =
result = b.sections[cpsLocals] result.add b.sections[cpsLocals]
if b.frameLen > 0: 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[cpsInit])
@ -159,7 +159,7 @@ proc blockBody(b: var TBlock): Rope =
proc endBlock(p: BProc, blockEnd: Rope) = proc endBlock(p: BProc, blockEnd: Rope) =
let topBlock = p.blocks.len-1 let topBlock = p.blocks.len-1
# the block is merged into the parent block # the block is merged into the parent block
p.blocks[topBlock-1].sections[cpsStmts].add(p.blocks[topBlock].blockBody) p.blocks[topBlock].blockBody(p.blocks[topBlock-1].sections[cpsStmts])
setLen(p.blocks, topBlock) setLen(p.blocks, topBlock)
# this is done after the block is popped so $n is # this is done after the block is popped so $n is
# properly indented when pretty printing is enabled # properly indented when pretty printing is enabled
@ -171,7 +171,7 @@ proc endBlock(p: BProc) =
var blockEnd: Rope var blockEnd: Rope
if frameLen > 0: if frameLen > 0:
blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope]) blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope])
if p.blocks[topBlock].label != nil: if p.blocks[topBlock].label.len != 0:
blockEnd.addf("} $1: ;$n", [p.blocks[topBlock].label]) blockEnd.addf("} $1: ;$n", [p.blocks[topBlock].label])
else: else:
blockEnd.addf("}$n", []) blockEnd.addf("}$n", [])
@ -279,17 +279,15 @@ proc genGotoVar(p: BProc; value: PNode) =
else: else:
lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope]) lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType): Rope proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; result: var Rope)
proc potentialValueInit(p: BProc; v: PSym; value: PNode): Rope = proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) =
if lfDynamicLib in v.loc.flags or sfThread in v.flags or p.hcrOn: if lfDynamicLib in v.loc.flags or sfThread in v.flags or p.hcrOn:
result = nil discard "nothing to do"
elif sfGlobal in v.flags and value != nil and isDeepConstExpr(value, p.module.compileToCpp) and elif sfGlobal in v.flags and value != nil and isDeepConstExpr(value, p.module.compileToCpp) and
p.withinLoop == 0 and not containsGarbageCollectedRef(v.typ): p.withinLoop == 0 and not containsGarbageCollectedRef(v.typ):
#echo "New code produced for ", v.name.s, " ", p.config $ value.info #echo "New code produced for ", v.name.s, " ", p.config $ value.info
result = genBracedInit(p, value, isConst = false, v.typ) genBracedInit(p, value, isConst = false, v.typ, result)
else:
result = nil
proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
if sfGoto in v.flags: if sfGoto in v.flags:
@ -297,8 +295,8 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
genGotoVar(p, value) genGotoVar(p, value)
return return
var targetProc = p var targetProc = p
var traverseProc: Rope var valueAsRope = ""
let valueAsRope = potentialValueInit(p, v, value) potentialValueInit(p, v, value, valueAsRope)
if sfGlobal in v.flags: if sfGlobal in v.flags:
if v.flags * {sfImportc, sfExportc} == {sfImportc} and if v.flags * {sfImportc, sfExportc} == {sfImportc} and
value.kind == nkEmpty and value.kind == nkEmpty and
@ -314,7 +312,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
# 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.
if valueAsRope == nil: if valueAsRope.len == 0:
var loc = v.loc var loc = v.loc
# When the native TLS is unavailable, a global thread-local variable needs # When the native TLS is unavailable, a global thread-local variable needs
@ -328,9 +326,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc) # if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
if sfExportc in v.flags and p.module.g.generatedHeader != nil: if sfExportc in v.flags and p.module.g.generatedHeader != nil:
genVarPrototype(p.module.g.generatedHeader, vn) genVarPrototype(p.module.g.generatedHeader, vn)
traverseProc = getTraverseProc(p, v) registerTraverseProc(p, v)
if traverseProc != nil and not p.hcrOn:
registerTraverseProc(p, v, traverseProc)
else: else:
let imm = isAssignedImmediately(p.config, value) let imm = isAssignedImmediately(p.config, value)
if imm and p.module.compileToCpp and p.splitDecls == 0 and if imm and p.module.compileToCpp and p.splitDecls == 0 and
@ -343,14 +339,14 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
var tmp: TLoc var tmp: TLoc
if value.kind in nkCallKinds and value[0].kind == nkSym and if value.kind in nkCallKinds and value[0].kind == nkSym and
sfConstructor in value[0].sym.flags: sfConstructor in value[0].sym.flags:
var params: Rope var params = newRopeAppender()
var argsCounter = 0
let typ = skipTypes(value[0].typ, abstractInst) let typ = skipTypes(value[0].typ, abstractInst)
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
for i in 1..<value.len: for i in 1..<value.len:
if params != nil: params.add(~", ")
assert(typ.len == typ.n.len) assert(typ.len == typ.n.len)
params.add(genOtherArg(p, value, i, typ)) genOtherArg(p, value, i, typ, params, argsCounter)
if params == nil: if params.len == 0:
lineF(p, cpsStmts, "$#;$n", [decl]) lineF(p, cpsStmts, "$#;$n", [decl])
else: else:
lineF(p, cpsStmts, "$#($#);$n", [decl, params]) lineF(p, cpsStmts, "$#($#);$n", [decl, params])
@ -361,7 +357,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
assignLocalVar(p, vn) assignLocalVar(p, vn)
initLocalVar(p, v, imm) initLocalVar(p, v, imm)
if traverseProc == nil: traverseProc = ~"NULL" let traverseProc = "NULL"
# If the var is in a block (control flow like if/while or a block) in global scope just # If the var is in a block (control flow like if/while or a block) in global scope just
# register the so called "global" so it can be used later on. There is no need to close # register the so called "global" so it can be used later on. There is no need to close
# and reopen of if (nim_hcr_do_init_) blocks because we are in one already anyway. # and reopen of if (nim_hcr_do_init_) blocks because we are in one already anyway.
@ -381,7 +377,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
lineCg(targetProc, cpsStmts, "if (hcrRegisterGlobal($3, \"$1\", sizeof($2), $4, (void**)&$1))$N", lineCg(targetProc, cpsStmts, "if (hcrRegisterGlobal($3, \"$1\", sizeof($2), $4, (void**)&$1))$N",
[v.loc.r, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc]) [v.loc.r, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc])
startBlock(targetProc) startBlock(targetProc)
if value.kind != nkEmpty and valueAsRope == nil: if value.kind != nkEmpty and valueAsRope.len == 0:
genLineDir(targetProc, vn) genLineDir(targetProc, vn)
loadInto(targetProc, vn, value, v.loc) loadInto(targetProc, vn, value, v.loc)
if forHcr: if forHcr:
@ -560,7 +556,9 @@ proc genComputedGoto(p: BProc; n: PNode) =
return return
let val = getOrdValue(it[j]) let val = getOrdValue(it[j])
lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(toInt64(val)+id+1)]) var lit = newRopeAppender()
intLiteral(toInt64(val)+id+1, lit)
lineF(p, cpsStmts, "TMP$#_:$n", [lit])
genStmts(p, it.lastSon) genStmts(p, it.lastSon)
@ -614,8 +612,9 @@ proc genWhileStmt(p: BProc, t: PNode) =
p.blocks[p.breakIdx].isLoop = true p.blocks[p.breakIdx].isLoop = true
initLocExpr(p, t[0], a) initLocExpr(p, t[0], a)
if (t[0].kind != nkIntLit) or (t[0].intVal == 0): if (t[0].kind != nkIntLit) or (t[0].intVal == 0):
let label = assignLabel(p.blocks[p.breakIdx]) lineF(p, cpsStmts, "if (!$1) goto ", [rdLoc(a)])
lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label]) assignLabel(p.blocks[p.breakIdx], p.s(cpsStmts))
lineF(p, cpsStmts, ";$n", [])
genStmts(p, loopBody) genStmts(p, loopBody)
if optProfiler in p.options: if optProfiler in p.options:
@ -702,12 +701,12 @@ proc genBreakStmt(p: BProc, t: PNode) =
while idx >= 0 and not p.blocks[idx].isLoop: dec idx while idx >= 0 and not p.blocks[idx].isLoop: dec idx
if idx < 0 or not p.blocks[idx].isLoop: if idx < 0 or not p.blocks[idx].isLoop:
internalError(p.config, t.info, "no loop to break") internalError(p.config, t.info, "no loop to break")
let label = assignLabel(p.blocks[idx]) p.blocks[idx].label = "LA" & p.blocks[idx].id.rope
blockLeaveActions(p, blockLeaveActions(p,
p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
p.inExceptBlockLen - p.blocks[idx].nestedExceptStmts) p.inExceptBlockLen - p.blocks[idx].nestedExceptStmts)
genLineDir(p, t) genLineDir(p, t)
lineF(p, cpsStmts, "goto $1;$n", [label]) lineF(p, cpsStmts, "goto $1;$n", [p.blocks[idx].label])
proc raiseExit(p: BProc) = proc raiseExit(p: BProc) =
assert p.config.exc == excGoto assert p.config.exc == excGoto
@ -729,21 +728,19 @@ proc finallyActions(p: BProc) =
if finallyBlock != nil: if finallyBlock != nil:
genSimpleBlock(p, finallyBlock[0]) genSimpleBlock(p, finallyBlock[0])
proc raiseInstr(p: BProc): Rope = proc raiseInstr(p: BProc; result: var Rope) =
if p.config.exc == excGoto: if p.config.exc == excGoto:
let L = p.nestedTryStmts.len let L = p.nestedTryStmts.len
if L == 0: if L == 0:
p.flags.incl beforeRetNeeded p.flags.incl beforeRetNeeded
# easy case, simply goto 'ret': # easy case, simply goto 'ret':
result = ropecg(p.module, "goto BeforeRet_;$n", []) result.add ropecg(p.module, "goto BeforeRet_;$n", [])
else: else:
# raise inside an 'except' must go to the finally block, # raise inside an 'except' must go to the finally block,
# raise outside an 'except' block must go to the 'except' list. # raise outside an 'except' block must go to the 'except' list.
result = ropecg(p.module, "goto LA$1_;$n", result.add ropecg(p.module, "goto LA$1_;$n",
[p.nestedTryStmts[L-1].label]) [p.nestedTryStmts[L-1].label])
# + ord(p.nestedTryStmts[L-1].inExcept)]) # + ord(p.nestedTryStmts[L-1].inExcept)])
else:
result = nil
proc genRaiseStmt(p: BProc, t: PNode) = proc genRaiseStmt(p: BProc, t: PNode) =
if t[0].kind != nkEmpty: if t[0].kind != nkEmpty:
@ -772,12 +769,10 @@ proc genRaiseStmt(p: BProc, t: PNode) =
genLineDir(p, t) genLineDir(p, t)
# reraise the last exception: # reraise the last exception:
if p.config.exc == excCpp: if p.config.exc == excCpp:
line(p, cpsStmts, ~"throw;$n") line(p, cpsStmts, "throw;\n")
else: else:
linefmt(p, cpsStmts, "#reraiseException();$n", []) linefmt(p, cpsStmts, "#reraiseException();$n", [])
let gotoInstr = raiseInstr(p) raiseInstr(p, p.s(cpsStmts))
if gotoInstr != nil:
line(p, cpsStmts, gotoInstr)
template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
rangeFormat, eqFormat: FormatStr, labl: TLabel) = rangeFormat, eqFormat: FormatStr, labl: TLabel) =
@ -885,9 +880,11 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n", linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n",
[rdLoc(a), bitMask]) [rdLoc(a), bitMask])
for j in 0..high(branches): for j in 0..high(branches):
if branches[j] != nil: if branches[j] != "":
var lit = newRopeAppender()
intLiteral(j, lit)
lineF(p, cpsStmts, "case $1: $n$2break;$n", lineF(p, cpsStmts, "case $1: $n$2break;$n",
[intLiteral(j), branches[j]]) [lit, branches[j]])
lineF(p, cpsStmts, "}$n", []) # else statement: lineF(p, cpsStmts, "}$n", []) # else statement:
if t[^1].kind != nkOfBranch: if t[^1].kind != nkOfBranch:
lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)]) lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)])
@ -921,16 +918,22 @@ proc genCaseRange(p: BProc, branch: PNode) =
for j in 0..<branch.len-1: for j in 0..<branch.len-1:
if branch[j].kind == nkRange: if branch[j].kind == nkRange:
if hasSwitchRange in CC[p.config.cCompiler].props: if hasSwitchRange in CC[p.config.cCompiler].props:
lineF(p, cpsStmts, "case $1 ... $2:$n", [ var litA = newRopeAppender()
genLiteral(p, branch[j][0]), var litB = newRopeAppender()
genLiteral(p, branch[j][1])]) genLiteral(p, branch[j][0], litA)
genLiteral(p, branch[j][1], litB)
lineF(p, cpsStmts, "case $1 ... $2:$n", [litA, litB])
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)]) var litA = newRopeAppender()
genLiteral(p, v, litA)
lineF(p, cpsStmts, "case $1:$n", [litA])
inc(v.intVal) inc(v.intVal)
else: else:
lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, branch[j])]) var litA = newRopeAppender()
genLiteral(p, branch[j], litA)
lineF(p, cpsStmts, "case $1:$n", [litA])
proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) = proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
# analyse 'case' statement: # analyse 'case' statement:
@ -942,7 +945,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
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: ""
# generate switch part (might be empty): # generate switch part (might be empty):
if splitPoint+1 < n.len: if splitPoint+1 < n.len:
@ -963,7 +966,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
if (hasAssume in CC[p.config.cCompiler].props) and not hasDefault: if (hasAssume in CC[p.config.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 != "": 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)
@ -1064,7 +1067,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
linefmt(p, cpsStmts, "#popCurrentException();$n", []) linefmt(p, cpsStmts, "#popCurrentException();$n", [])
endBlock(p) endBlock(p)
else: else:
var orExpr = Rope(nil) var orExpr = newRopeAppender()
var exvar = PNode(nil) var exvar = PNode(nil)
for j in 0..<t[i].len - 1: for j in 0..<t[i].len - 1:
var typeNode = t[i][j] var typeNode = t[i][j]
@ -1075,7 +1078,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
if isImportedException(typeNode.typ, p.config): if isImportedException(typeNode.typ, p.config):
hasImportedCppExceptions = true hasImportedCppExceptions = true
else: else:
if orExpr != nil: orExpr.add("||") if orExpr.len != 0: orExpr.add("||")
let checkFor = if optTinyRtti in p.config.globalOptions: let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, typeNode.typ) genTypeInfo2Name(p.module, typeNode.typ)
else: else:
@ -1083,14 +1086,15 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
if orExpr != nil: if orExpr.len != 0:
if hasIf: if hasIf:
startBlock(p, "else if ($1) {$n", [orExpr]) startBlock(p, "else if ($1) {$n", [orExpr])
else: else:
startBlock(p, "if ($1) {$n", [orExpr]) startBlock(p, "if ($1) {$n", [orExpr])
hasIf = true hasIf = true
if exvar != nil: if exvar != nil:
fillLoc(exvar.sym.loc, locTemp, exvar, mangleLocalName(p, exvar.sym), OnStack) fillLocalName(p, exvar.sym)
fillLoc(exvar.sym.loc, locTemp, exvar, OnStack)
linefmt(p, cpsStmts, "$1 $2 = T$3_;$n", [getTypeDesc(p.module, exvar.sym.typ), linefmt(p, cpsStmts, "$1 $2 = T$3_;$n", [getTypeDesc(p.module, exvar.sym.typ),
rdLoc(exvar.sym.loc), rope(etmp+1)]) rdLoc(exvar.sym.loc), rope(etmp+1)])
# we handled the error: # we handled the error:
@ -1131,7 +1135,8 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
typeNode = t[i][j][1] typeNode = t[i][j][1]
if isImportedException(typeNode.typ, p.config): if isImportedException(typeNode.typ, p.config):
let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:` let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:`
fillLoc(exvar.sym.loc, locTemp, exvar, mangleLocalName(p, exvar.sym), OnStack) fillLocalName(p, exvar.sym)
fillLoc(exvar.sym.loc, locTemp, exvar, OnStack)
startBlock(p, "catch ($1& $2) {$n", getTypeDesc(p.module, typeNode.typ), rdLoc(exvar.sym.loc)) startBlock(p, "catch ($1& $2) {$n", getTypeDesc(p.module, typeNode.typ), rdLoc(exvar.sym.loc))
genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type
endBlock(p) endBlock(p)
@ -1184,7 +1189,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
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)
genLineDir(p, t) genLineDir(p, t)
discard cgsym(p.module, "popCurrentExceptionEx") cgsym(p.module, "popCurrentExceptionEx")
let fin = if t[^1].kind == nkFinally: t[^1] else: nil let fin = if t[^1].kind == nkFinally: t[^1] else: nil
p.nestedTryStmts.add((fin, false, 0.Natural)) p.nestedTryStmts.add((fin, false, 0.Natural))
startBlock(p, "try {$n") startBlock(p, "try {$n")
@ -1210,7 +1215,8 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
for j in 0..<t[i].len-1: for j in 0..<t[i].len-1:
if t[i][j].isInfixAs(): if t[i][j].isInfixAs():
let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:` let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:`
fillLoc(exvar.sym.loc, locTemp, exvar, mangleLocalName(p, exvar.sym), OnUnknown) fillLocalName(p, exvar.sym)
fillLoc(exvar.sym.loc, locTemp, exvar, OnUnknown)
startBlock(p, "catch ($1& $2) {$n", getTypeDesc(p.module, t[i][j][1].typ), rdLoc(exvar.sym.loc)) startBlock(p, "catch ($1& $2) {$n", getTypeDesc(p.module, t[i][j][1].typ), rdLoc(exvar.sym.loc))
else: else:
startBlock(p, "catch ($1&) {$n", getTypeDesc(p.module, t[i][j].typ)) startBlock(p, "catch ($1&) {$n", getTypeDesc(p.module, t[i][j].typ))
@ -1225,7 +1231,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
# finally requires catch all presence # finally requires catch all presence
startBlock(p, "catch (...) {$n") startBlock(p, "catch (...) {$n")
genStmts(p, t[^1][0]) genStmts(p, t[^1][0])
line(p, cpsStmts, ~"throw;$n") line(p, cpsStmts, "throw;\n")
endBlock(p) endBlock(p)
genSimpleBlock(p, t[^1][0]) genSimpleBlock(p, t[^1][0])
@ -1287,10 +1293,10 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", []) linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", [])
expr(p, t[i][0], d) expr(p, t[i][0], d)
else: else:
var orExpr: Rope = nil var orExpr = newRopeAppender()
for j in 0..<t[i].len - 1: for j in 0..<t[i].len - 1:
assert(t[i][j].kind == nkType) assert(t[i][j].kind == nkType)
if orExpr != nil: orExpr.add("||") if orExpr.len != 0: orExpr.add("||")
let checkFor = if optTinyRtti in p.config.globalOptions: let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, t[i][j].typ) genTypeInfo2Name(p.module, t[i][j].typ)
else: else:
@ -1372,7 +1378,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
else: else:
p.flags.incl noSafePoints p.flags.incl noSafePoints
genLineDir(p, t) genLineDir(p, t)
discard cgsym(p.module, "Exception") cgsym(p.module, "Exception")
var safePoint: Rope var safePoint: Rope
if not quirkyExceptions: if not quirkyExceptions:
safePoint = getTempName(p.module) safePoint = getTempName(p.module)
@ -1389,7 +1395,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
if isDefined(p.config, "vcc") or isDefined(p.config, "clangcl"): if isDefined(p.config, "vcc") or isDefined(p.config, "clangcl"):
# For the vcc compiler, use `setjmp()` with one argument. # For the vcc compiler, use `setjmp()` with one argument.
# See https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setjmp?view=msvc-170 # See https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setjmp?view=msvc-170
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint]) linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
else: else:
# The Windows `_setjmp()` takes two arguments, with the second being an # The Windows `_setjmp()` takes two arguments, with the second being an
# undocumented buffer used by the SEH mechanism for stack unwinding. # undocumented buffer used by the SEH mechanism for stack unwinding.
@ -1431,10 +1437,10 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
linefmt(p, cpsStmts, "#popCurrentException();$n", []) linefmt(p, cpsStmts, "#popCurrentException();$n", [])
endBlock(p) endBlock(p)
else: else:
var orExpr: Rope = nil var orExpr = newRopeAppender()
for j in 0..<t[i].len - 1: for j in 0..<t[i].len - 1:
assert(t[i][j].kind == nkType) assert(t[i][j].kind == nkType)
if orExpr != nil: orExpr.add("||") if orExpr.len != 0: orExpr.add("||")
let checkFor = if optTinyRtti in p.config.globalOptions: let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, t[i][j].typ) genTypeInfo2Name(p.module, t[i][j].typ)
else: else:
@ -1466,7 +1472,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
if not quirkyExceptions: if not quirkyExceptions:
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint]) linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint])
proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope = proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
var res = "" var res = ""
for it in t.sons: for it in t.sons:
case it.kind case it.kind
@ -1482,13 +1488,8 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
res.add($getTypeDesc(p.module, sym.typ)) res.add($getTypeDesc(p.module, sym.typ))
else: else:
discard getTypeDesc(p.module, skipTypes(sym.typ, abstractPtrs)) discard getTypeDesc(p.module, skipTypes(sym.typ, abstractPtrs))
var r = sym.loc.r fillBackendName(p.module, sym)
if r == nil: res.add($sym.loc.r)
# if no name has already been given,
# it doesn't matter much:
r = mangleName(p.module, sym)
sym.loc.r = r # but be consequent!
res.add($r)
of nkTypeOfExpr: of nkTypeOfExpr:
res.add($getTypeDesc(p.module, it.typ)) res.add($getTypeDesc(p.module, it.typ))
else: else:
@ -1513,12 +1514,13 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
result.add("\\n\"\n") result.add("\\n\"\n")
else: else:
res.add("\L") res.add("\L")
result = res.rope result.add res.rope
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 = newRopeAppender()
genAsmOrEmitStmt(p, t, isAsmStmt=true, s)
# see bug #2362, "top level asm statements" seem to be a mis-feature # 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 # but even if we don't do this, the example in #2362 cannot possibly
# work: # work:
@ -1526,7 +1528,8 @@ proc genAsmStmt(p: BProc, t: PNode) =
# top level asm statement? # top level asm statement?
p.module.s[cfsProcHeaders].add runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s]) p.module.s[cfsProcHeaders].add runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s])
else: else:
p.s(cpsStmts).add indentLine(p, runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s])) addIndent p, p.s(cpsStmts)
p.s(cpsStmts).add runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s])
proc determineSection(n: PNode): TCFileSection = proc determineSection(n: PNode): TCFileSection =
result = cfsProcHeaders result = cfsProcHeaders
@ -1537,7 +1540,8 @@ proc determineSection(n: PNode): TCFileSection =
elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders
proc genEmit(p: BProc, t: PNode) = proc genEmit(p: BProc, t: PNode) =
var s = genAsmOrEmitStmt(p, t[1]) var s = newRopeAppender()
genAsmOrEmitStmt(p, t[1], false, s)
if p.prc == nil: if p.prc == nil:
# top level emit pragma? # top level emit pragma?
let section = determineSection(t[1]) let section = determineSection(t[1])
@ -1562,10 +1566,12 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
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)])
var lit = newRopeAppender()
intLiteral(toInt64(lengthOrd(p.config, field.typ))+1, lit)
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(toInt64(lengthOrd(p.config, field.typ))+1)]) lit])
when false: when false:
proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) = proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) =

View file

@ -44,13 +44,13 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
m.s[cfsVars].addf(" $1;$n", [s.loc.r]) m.s[cfsVars].addf(" $1;$n", [s.loc.r])
proc generateThreadLocalStorage(m: BModule) = proc generateThreadLocalStorage(m: BModule) =
if m.g.nimtv != nil and (usesThreadVars in m.flags or sfMainModule in m.module.flags): if m.g.nimtv != "" and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
for t in items(m.g.nimtvDeps): discard getTypeDesc(m, t) for t in items(m.g.nimtvDeps): discard getTypeDesc(m, t)
finishTypeDescriptions(m) finishTypeDescriptions(m)
m.s[cfsSeqTypes].addf("typedef struct {$1} NimThreadVars;$n", [m.g.nimtv]) m.s[cfsSeqTypes].addf("typedef struct {$1} NimThreadVars;$n", [m.g.nimtv])
proc generateThreadVarsSize(m: BModule) = proc generateThreadVarsSize(m: BModule) =
if m.g.nimtv != nil: if m.g.nimtv != "":
let externc = if m.config.backend == backendCpp or let externc = if m.config.backend == backendCpp or
sfCompileToCpp in m.module.flags: "extern \"C\" " sfCompileToCpp in m.module.flags: "extern \"C\" "
else: "" else: ""

View file

@ -34,7 +34,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
if (n[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc") if (n[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
var p = c.p var p = c.p
let disc = n[0].sym let disc = n[0].sym
if disc.loc.r == nil: fillObjectFields(c.p.module, typ) if disc.loc.r == "": fillObjectFields(c.p.module, typ)
if disc.loc.t == nil: if disc.loc.t == nil:
internalError(c.p.config, n.info, "genTraverseProc()") internalError(c.p.config, n.info, "genTraverseProc()")
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r]) lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
@ -51,7 +51,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
of nkSym: of nkSym:
let field = n.sym let field = n.sym
if field.typ.kind == tyVoid: return if field.typ.kind == tyVoid: return
if field.loc.r == nil: fillObjectFields(c.p.module, typ) if field.loc.r == "": fillObjectFields(c.p.module, typ)
if field.loc.t == nil: if field.loc.t == nil:
internalError(c.p.config, n.info, "genTraverseProc()") internalError(c.p.config, n.info, "genTraverseProc()")
genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t) genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t)
@ -76,7 +76,8 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
let arraySize = lengthOrd(c.p.config, typ[0]) let arraySize = lengthOrd(c.p.config, typ[0])
var i: TLoc var i: TLoc
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i) getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i)
let oldCode = p.s(cpsStmts) var oldCode = p.s(cpsStmts)
freeze oldCode
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.r, arraySize]) [i.r, arraySize])
let oldLen = p.s(cpsStmts).len let oldLen = p.s(cpsStmts).len
@ -120,7 +121,8 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
assert typ.kind == tySequence assert typ.kind == tySequence
var i: TLoc var i: TLoc
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i) getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i)
let oldCode = p.s(cpsStmts) var oldCode = p.s(cpsStmts)
freeze oldCode
var a: TLoc var a: TLoc
a.r = accessor a.r = accessor

View file

@ -13,8 +13,6 @@
import sighashes, modulegraphs import sighashes, modulegraphs
proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope
proc isKeyword(w: PIdent): bool = proc isKeyword(w: PIdent): bool =
# Nim and C++ share some keywords # Nim and C++ share some keywords
# it's more efficient to test the whole Nim keywords range # it's more efficient to test the whole Nim keywords range
@ -35,10 +33,9 @@ proc mangleField(m: BModule; name: PIdent): string =
if isKeyword(name): if isKeyword(name):
result.add "_0" result.add "_0"
proc mangleName(m: BModule; s: PSym): Rope = proc fillBackendName(m: BModule; s: PSym) =
result = s.loc.r if s.loc.r == "":
if result == nil: var result = s.name.s.mangle.rope
result = s.name.s.mangle.rope
result.add "__" result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_" result.add "_"
@ -49,12 +46,11 @@ proc mangleName(m: BModule; s: PSym): Rope =
s.loc.r = result s.loc.r = result
writeMangledName(m.ndi, s, m.config) writeMangledName(m.ndi, s, m.config)
proc mangleParamName(m: BModule; s: PSym): Rope = proc fillParamName(m: BModule; s: PSym) =
## we cannot use 'sigConflicts' here since we have a BModule, not a BProc. ## 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 ## Fortunately C's scoping rules are sane enough so that that doesn't
## cause any trouble. ## cause any trouble.
result = s.loc.r if s.loc.r == "":
if result == nil:
var res = s.name.s.mangle var res = s.name.s.mangle
# Take into account if HCR is on because of the following scenario: # Take into account if HCR is on because of the following scenario:
# if a module gets imported and it has some more importc symbols in it, # if a module gets imported and it has some more importc symbols in it,
@ -74,20 +70,16 @@ proc mangleParamName(m: BModule; s: PSym): Rope =
# executable file for the main module, which is running (or both!) -> error. # executable file for the main module, which is running (or both!) -> error.
if m.hcrOn or isKeyword(s.name) or m.g.config.cppDefines.contains(res): if m.hcrOn or isKeyword(s.name) or m.g.config.cppDefines.contains(res):
res.add "_0" res.add "_0"
result = res.rope s.loc.r = res.rope
s.loc.r = result
writeMangledName(m.ndi, s, m.config) writeMangledName(m.ndi, s, m.config)
proc mangleLocalName(p: BProc; s: PSym): Rope = proc fillLocalName(p: BProc; s: PSym) =
assert s.kind in skLocalVars+{skTemp} assert s.kind in skLocalVars+{skTemp}
#assert sfGlobal notin s.flags #assert sfGlobal notin s.flags
result = s.loc.r if s.loc.r == "":
if result == nil:
var key = s.name.s.mangle var key = s.name.s.mangle
when not defined(nimSeqsV2):
shallow(key)
let counter = p.sigConflicts.getOrDefault(key) let counter = p.sigConflicts.getOrDefault(key)
result = key.rope var result = key.rope
if s.kind == skTemp: if s.kind == skTemp:
# speed up conflict search for temps (these are quite common): # speed up conflict search for temps (these are quite common):
if counter != 0: result.add "_" & rope(counter+1) if counter != 0: result.add "_" & rope(counter+1)
@ -103,8 +95,6 @@ proc scopeMangledParam(p: BProc; param: PSym) =
## generate unique identifiers reliably (consider that ``var a = a`` is ## generate unique identifiers reliably (consider that ``var a = a`` is
## even an idiom in Nim). ## even an idiom in Nim).
var key = param.name.s.mangle var key = param.name.s.mangle
when not defined(nimSeqsV2):
shallow(key)
p.sigConflicts.inc(key) p.sigConflicts.inc(key)
const const
@ -112,13 +102,12 @@ const
tyDistinct, tyRange, tyStatic, tyAlias, tySink, tyDistinct, tyRange, tyStatic, tyAlias, tySink,
tyInferred, tyOwned} tyInferred, tyOwned}
proc typeName(typ: PType): Rope = proc typeName(typ: PType; result: var Rope) =
let typ = typ.skipTypes(irrelevantForBackend) let typ = typ.skipTypes(irrelevantForBackend)
result = result.add $typ.kind
if typ.sym != nil and typ.kind in {tyObject, tyEnum}: if typ.sym != nil and typ.kind in {tyObject, tyEnum}:
rope($typ.kind & '_' & typ.sym.name.s.mangle) result.add "_"
else: result.add typ.sym.name.s.mangle
rope($typ.kind)
proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope = proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
var t = typ var t = typ
@ -131,14 +120,17 @@ proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
else: else:
break break
let typ = if typ.kind in {tyAlias, tySink, tyOwned}: typ.lastSon else: typ let typ = if typ.kind in {tyAlias, tySink, tyOwned}: typ.lastSon else: typ
if typ.loc.r == nil: if typ.loc.r == "":
typ.loc.r = typ.typeName & $sig typ.typeName(typ.loc.r)
typ.loc.r.add $sig
else: else:
when defined(debugSigHashes): when defined(debugSigHashes):
# check consistency: # check consistency:
assert($typ.loc.r == $(typ.typeName & $sig)) var tn = newRopeAppender()
typ.typeName(tn)
assert($typ.loc.r == $(tn & $sig))
result = typ.loc.r result = typ.loc.r
if result == nil: internalError(m.config, "getTypeName: " & $typ.kind) if result == "": internalError(m.config, "getTypeName: " & $typ.kind)
proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind =
case int(getSize(conf, typ)) case int(getSize(conf, typ))
@ -266,7 +258,7 @@ proc addAbiCheck(m: BModule, t: PType, name: Rope) =
proc fillResult(conf: ConfigRef; param: PNode, proctype: PType) = proc fillResult(conf: ConfigRef; param: PNode, proctype: PType) =
fillLoc(param.sym.loc, locParam, param, ~"Result", fillLoc(param.sym.loc, locParam, param, "Result",
OnStack) OnStack)
let t = param.sym.typ let t = param.sym.typ
if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, proctype): if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, proctype):
@ -292,11 +284,11 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
of tyString: of tyString:
case detectStrVersion(m) case detectStrVersion(m)
of 2: of 2:
discard cgsym(m, "NimStrPayload") cgsym(m, "NimStrPayload")
discard cgsym(m, "NimStringV2") cgsym(m, "NimStringV2")
result = typeNameOrLiteral(m, typ, "NimStringV2") result = typeNameOrLiteral(m, typ, "NimStringV2")
else: else:
discard cgsym(m, "NimStringDesc") cgsym(m, "NimStringDesc")
result = typeNameOrLiteral(m, typ, "NimStringDesc*") result = typeNameOrLiteral(m, typ, "NimStringDesc*")
of tyCstring: result = typeNameOrLiteral(m, typ, "NCSTRING") of tyCstring: result = typeNameOrLiteral(m, typ, "NCSTRING")
of tyBool: result = typeNameOrLiteral(m, typ, "NIM_BOOL") of tyBool: result = typeNameOrLiteral(m, typ, "NIM_BOOL")
@ -310,11 +302,11 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
else: internalError(m.config, "tyStatic for getSimpleTypeDesc") else: internalError(m.config, "tyStatic for getSimpleTypeDesc")
of tyGenericInst, tyAlias, tySink, tyOwned: of tyGenericInst, tyAlias, tySink, tyOwned:
result = getSimpleTypeDesc(m, lastSon typ) result = getSimpleTypeDesc(m, lastSon typ)
else: result = nil else: result = ""
if result != nil and typ.isImportedType(): if result != "" and typ.isImportedType():
let sig = hashType typ let sig = hashType typ
if cacheGetType(m.typeCache, sig) == nil: if cacheGetType(m.typeCache, sig) == "":
m.typeCache[sig] = result m.typeCache[sig] = result
proc pushType(m: BModule, typ: PType) = proc pushType(m: BModule, typ: PType) =
@ -327,7 +319,7 @@ proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope =
if typ == nil: result = rope("void") if typ == nil: result = rope("void")
else: else:
result = getSimpleTypeDesc(m, typ) result = getSimpleTypeDesc(m, typ)
if result == nil: result = cacheGetType(m.typeCache, sig) if result == "": result = cacheGetType(m.typeCache, sig)
proc structOrUnion(t: PType): Rope = proc structOrUnion(t: PType): Rope =
let cachedUnion = rope("union") let cachedUnion = rope("union")
@ -348,9 +340,9 @@ proc seqStar(m: BModule): string =
proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
result = cacheGetType(m.forwTypeCache, sig) result = cacheGetType(m.forwTypeCache, sig)
if result != nil: return if result != "": return
result = getTypePre(m, typ, sig) result = getTypePre(m, typ, sig)
if result != nil: return if result != "": return
let concrete = typ.skipTypes(abstractInst) let concrete = typ.skipTypes(abstractInst)
case concrete.kind case concrete.kind
of tySequence, tyTuple, tyObject: of tySequence, tyTuple, tyObject:
@ -382,7 +374,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): R
internalError(m.config, "cannot map the empty seq type to a C type") internalError(m.config, "cannot map the empty seq type to a C type")
result = cacheGetType(m.forwTypeCache, sig) result = cacheGetType(m.forwTypeCache, sig)
if result == nil: if result == "":
result = getTypeName(m, t, sig) result = getTypeName(m, t, sig)
if not isImportedType(t): if not isImportedType(t):
m.forwTypeCache[sig] = result m.forwTypeCache[sig] = result
@ -390,7 +382,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): R
let payload = result & "_Content" let payload = result & "_Content"
addForwardStructFormat(m, rope"struct", payload) addForwardStructFormat(m, rope"struct", payload)
if cacheGetType(m.typeCache, sig) == nil: if cacheGetType(m.typeCache, sig) == "":
m.typeCache[sig] = result m.typeCache[sig] = result
#echo "adding ", sig, " ", typeToString(t), " ", m.module.name.s #echo "adding ", sig, " ", typeToString(t), " ", m.module.name.s
appcg(m, m.s[cfsTypes], appcg(m, m.s[cfsTypes],
@ -411,7 +403,7 @@ proc getSeqPayloadType(m: BModule; t: PType): Rope =
proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) = proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) =
let sig = hashType(t) let sig = hashType(t)
let result = cacheGetType(m.typeCache, sig) let result = cacheGetType(m.typeCache, sig)
if result == nil: if result == "":
discard getTypeDescAux(m, t, check, skVar) discard getTypeDescAux(m, t, check, skVar)
else: else:
# little hack for now to prevent multiple definitions of the same # little hack for now to prevent multiple definitions of the same
@ -433,30 +425,31 @@ proc paramStorageLoc(param: PSym): TStorageLoc =
proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
check: var IntSet, declareEnvironment=true; check: var IntSet, declareEnvironment=true;
weakDep=false) = weakDep=false) =
params = nil params = ""
if t[0] == nil or isInvalidReturnType(m.config, t): if t[0] == nil or isInvalidReturnType(m.config, t):
rettype = ~"void" rettype = "void"
else: else:
rettype = getTypeDescAux(m, t[0], check, skResult) rettype = getTypeDescAux(m, t[0], check, skResult)
for i in 1..<t.n.len: for i in 1..<t.n.len:
if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams") if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams")
var param = t.n[i].sym var param = t.n[i].sym
if isCompileTimeOnly(param.typ): continue if isCompileTimeOnly(param.typ): continue
if params != nil: params.add(~", ") if params != "": params.add(", ")
fillLoc(param.loc, locParam, t.n[i], mangleParamName(m, param), fillParamName(m, param)
fillLoc(param.loc, locParam, t.n[i],
param.paramStorageLoc) param.paramStorageLoc)
if ccgIntroducedPtr(m.config, param, t[0]): if ccgIntroducedPtr(m.config, param, t[0]):
params.add(getTypeDescWeak(m, param.typ, check, skParam)) params.add(getTypeDescWeak(m, param.typ, check, skParam))
params.add(~"*") params.add("*")
incl(param.loc.flags, lfIndirect) incl(param.loc.flags, lfIndirect)
param.loc.storage = OnUnknown param.loc.storage = OnUnknown
elif weakDep: elif weakDep:
params.add(getTypeDescWeak(m, param.typ, check, skParam)) params.add(getTypeDescWeak(m, param.typ, check, skParam))
else: else:
params.add(getTypeDescAux(m, param.typ, check, skParam)) params.add(getTypeDescAux(m, param.typ, check, skParam))
params.add(~" ") params.add(" ")
if sfNoalias in param.flags: if sfNoalias in param.flags:
params.add(~"NIM_NOALIAS ") params.add("NIM_NOALIAS ")
params.add(param.loc.r) params.add(param.loc.r)
# declare the len field for open arrays: # declare the len field for open arrays:
var arr = param.typ.skipTypes({tyGenericInst}) var arr = param.typ.skipTypes({tyGenericInst})
@ -471,7 +464,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
arr = arr[0].skipTypes({tySink}) arr = arr[0].skipTypes({tySink})
if t[0] != nil and isInvalidReturnType(m.config, t): if t[0] != nil and isInvalidReturnType(m.config, t):
var arr = t[0] var arr = t[0]
if params != nil: params.add(", ") if params != "": params.add(", ")
if mapReturnType(m.config, t[0]) != ctArray: if mapReturnType(m.config, t[0]) != ctArray:
if isHeaderFile in m.flags: if isHeaderFile in m.flags:
# still generates types for `--header` # still generates types for `--header`
@ -484,12 +477,12 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
params.add(getTypeDescAux(m, arr, check, skResult)) params.add(getTypeDescAux(m, arr, check, skResult))
params.addf(" Result", []) params.addf(" Result", [])
if t.callConv == ccClosure and declareEnvironment: if t.callConv == ccClosure and declareEnvironment:
if params != nil: params.add(", ") if params != "": params.add(", ")
params.add("void* ClE_0") params.add("void* ClE_0")
if tfVarargs in t.flags: if tfVarargs in t.flags:
if params != nil: params.add(", ") if params != "": params.add(", ")
params.add("...") params.add("...")
if params == nil: params.add("void)") if params == "": params.add("void)")
else: params.add(")") else: params.add(")")
params = "(" & params params = "(" & params
@ -498,30 +491,30 @@ proc mangleRecFieldName(m: BModule; field: PSym): Rope =
result = field.loc.r result = field.loc.r
else: else:
result = rope(mangleField(m, field.name)) result = rope(mangleField(m, field.name))
if result == nil: internalError(m.config, field.info, "mangleRecFieldName") if result == "": internalError(m.config, field.info, "mangleRecFieldName")
proc genRecordFieldsAux(m: BModule, n: PNode, proc genRecordFieldsAux(m: BModule, n: PNode,
rectype: PType, rectype: PType,
check: var IntSet, unionPrefix = ""): Rope = check: var IntSet; result: var Rope; unionPrefix = "") =
result = nil
case n.kind case n.kind
of nkRecList: of nkRecList:
for i in 0..<n.len: for i in 0..<n.len:
result.add(genRecordFieldsAux(m, n[i], rectype, check, unionPrefix)) genRecordFieldsAux(m, n[i], rectype, check, result, unionPrefix)
of nkRecCase: of nkRecCase:
if n[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux") if n[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux")
result.add(genRecordFieldsAux(m, n[0], rectype, check, unionPrefix)) genRecordFieldsAux(m, n[0], rectype, check, result, unionPrefix)
# prefix mangled name with "_U" to avoid clashes with other field names, # prefix mangled name with "_U" to avoid clashes with other field names,
# since identifiers are not allowed to start with '_' # since identifiers are not allowed to start with '_'
var unionBody: Rope = nil var unionBody: Rope = ""
for i in 1..<n.len: for i in 1..<n.len:
case n[i].kind case n[i].kind
of nkOfBranch, nkElse: of nkOfBranch, nkElse:
let k = lastSon(n[i]) let k = lastSon(n[i])
if k.kind != nkSym: if k.kind != nkSym:
let structName = "_" & mangleRecFieldName(m, n[0].sym) & "_" & $i let structName = "_" & mangleRecFieldName(m, n[0].sym) & "_" & $i
let a = genRecordFieldsAux(m, k, rectype, check, unionPrefix & $structName & ".") var a = newRopeAppender()
if a != nil: genRecordFieldsAux(m, k, rectype, check, a, unionPrefix & $structName & ".")
if a != "":
if tfPacked notin rectype.flags: if tfPacked notin rectype.flags:
unionBody.add("struct {") unionBody.add("struct {")
else: else:
@ -534,9 +527,9 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
if tfPacked in rectype.flags and hasAttribute notin CC[m.config.cCompiler].props: if tfPacked in rectype.flags and hasAttribute notin CC[m.config.cCompiler].props:
unionBody.addf("#pragma pack(pop)$n", []) unionBody.addf("#pragma pack(pop)$n", [])
else: else:
unionBody.add(genRecordFieldsAux(m, k, rectype, check, unionPrefix)) genRecordFieldsAux(m, k, rectype, check, unionBody, unionPrefix)
else: internalError(m.config, "genRecordFieldsAux(record case branch)") else: internalError(m.config, "genRecordFieldsAux(record case branch)")
if unionBody != nil: if unionBody != "":
result.addf("union{$n$1};$n", [unionBody]) result.addf("union{$n$1};$n", [unionBody])
of nkSym: of nkSym:
let field = n.sym let field = n.sym
@ -550,7 +543,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
# have to recurse via 'getTypeDescAux'. And not doing so prevents problems # have to recurse via 'getTypeDescAux'. And not doing so prevents problems
# with heavily templatized C++ code: # with heavily templatized C++ code:
if not isImportedCppType(rectype): if not isImportedCppType(rectype):
let noAlias = if sfNoalias in field.flags: ~" NIM_NOALIAS" else: nil let noAlias = if sfNoalias in field.flags: " NIM_NOALIAS" else: ""
let fieldType = field.loc.lode.typ.skipTypes(abstractInst) let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
if fieldType.kind == tyUncheckedArray: if fieldType.kind == tyUncheckedArray:
@ -568,7 +561,8 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
else: internalError(m.config, n.info, "genRecordFieldsAux()") else: internalError(m.config, n.info, "genRecordFieldsAux()")
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope = proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
result = genRecordFieldsAux(m, typ.n, typ, check) result = newRopeAppender()
genRecordFieldsAux(m, typ.n, typ, check, result)
proc fillObjectFields*(m: BModule; typ: PType) = proc fillObjectFields*(m: BModule; typ: PType) =
# sometimes generic objects are not consistently merged. We patch over # sometimes generic objects are not consistently merged. We patch over
@ -625,7 +619,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
result.addf(" {$n", [name]) result.addf(" {$n", [name])
let desc = getRecordFields(m, typ, check) let desc = getRecordFields(m, typ, check)
if desc == nil and not hasField: if desc == "" and not hasField:
result.addf("char dummy;$n", []) result.addf("char dummy;$n", [])
else: else:
result.add(desc) result.add(desc)
@ -636,11 +630,11 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
proc getTupleDesc(m: BModule, typ: PType, name: Rope, proc getTupleDesc(m: BModule, typ: PType, name: Rope,
check: var IntSet): Rope = check: var IntSet): Rope =
result = "$1 $2 {$n" % [structOrUnion(typ), name] result = "$1 $2 {$n" % [structOrUnion(typ), name]
var desc: Rope = nil var desc: Rope = ""
for i in 0..<typ.len: for i in 0..<typ.len:
desc.addf("$1 Field$2;$n", desc.addf("$1 Field$2;$n",
[getTypeDescAux(m, typ[i], check, skField), rope(i)]) [getTypeDescAux(m, typ[i], check, skField), rope(i)])
if desc == nil: result.add("char dummy;\L") if desc == "": result.add("char dummy;\L")
else: result.add(desc) else: result.add(desc)
result.add("};\L") result.add("};\L")
@ -679,7 +673,7 @@ proc getOpenArrayDesc(m: BModule, t: PType, check: var IntSet; kind: TSymKind):
result = getTypeDescWeak(m, t[0], check, kind) & "*" result = getTypeDescWeak(m, t[0], check, kind) & "*"
else: else:
result = cacheGetType(m.typeCache, sig) result = cacheGetType(m.typeCache, sig)
if result == nil: if result == "":
result = getTypeName(m, t, sig) result = getTypeName(m, t, sig)
m.typeCache[sig] = result m.typeCache[sig] = result
let elemType = getTypeDescWeak(m, t[0], check, kind) let elemType = getTypeDescWeak(m, t[0], check, kind)
@ -705,7 +699,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
addAbiCheck(m, t, result) addAbiCheck(m, t, result)
result = getTypePre(m, t, sig) result = getTypePre(m, t, sig)
if result != nil and t.kind != tyOpenArray: if result != "" and t.kind != tyOpenArray:
excl(check, t.id) excl(check, t.id)
return return
case t.kind case t.kind
@ -748,7 +742,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
result = getOpenArrayDesc(m, t, check, kind) result = getOpenArrayDesc(m, t, check, kind)
of tyEnum: of tyEnum:
result = cacheGetType(m.typeCache, sig) result = cacheGetType(m.typeCache, sig)
if result == nil: if result == "":
result = getTypeName(m, origTyp, sig) result = getTypeName(m, origTyp, sig)
if not (isImportedCppType(t) or if not (isImportedCppType(t) or
(sfImportc in t.sym.flags and t.sym.magic == mNone)): (sfImportc in t.sym.flags and t.sym.magic == mNone)):
@ -796,12 +790,12 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
# we cannot use getTypeForward here because then t would be associated # we cannot use getTypeForward here because then t would be associated
# with the name of the struct, not with the pointer to the struct: # with the name of the struct, not with the pointer to the struct:
result = cacheGetType(m.forwTypeCache, sig) result = cacheGetType(m.forwTypeCache, sig)
if result == nil: if result == "":
result = getTypeName(m, origTyp, sig) result = getTypeName(m, origTyp, sig)
if not isImportedType(t): if not isImportedType(t):
addForwardStructFormat(m, structOrUnion(t), result) addForwardStructFormat(m, structOrUnion(t), result)
m.forwTypeCache[sig] = result m.forwTypeCache[sig] = result
assert(cacheGetType(m.typeCache, sig) == nil) assert(cacheGetType(m.typeCache, sig) == "")
m.typeCache[sig] = result & seqStar(m) m.typeCache[sig] = result & seqStar(m)
if not isImportedType(t): if not isImportedType(t):
if skipTypes(t[0], typedescInst).kind != tyEmpty: if skipTypes(t[0], typedescInst).kind != tyEmpty:
@ -837,25 +831,26 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
[foo, result, rope(n)]) [foo, result, rope(n)])
of tyObject, tyTuple: of tyObject, tyTuple:
if isImportedCppType(t) and origTyp.kind == tyGenericInst: if isImportedCppType(t) and origTyp.kind == tyGenericInst:
let cppName = getTypeName(m, t, sig) let cppNameAsRope = getTypeName(m, t, sig)
let cppName = $cppNameAsRope
var i = 0 var i = 0
var chunkStart = 0 var chunkStart = 0
template addResultType(ty: untyped) = template addResultType(ty: untyped) =
if ty == nil or ty.kind == tyVoid: if ty == nil or ty.kind == tyVoid:
result.add(~"void") result.add("void")
elif ty.kind == tyStatic: elif ty.kind == tyStatic:
internalAssert m.config, ty.n != nil internalAssert m.config, ty.n != nil
result.add ty.n.renderTree result.add ty.n.renderTree
else: else:
result.add getTypeDescAux(m, ty, check, kind) result.add getTypeDescAux(m, ty, check, kind)
while i < cppName.data.len: while i < cppName.len:
if cppName.data[i] == '\'': if cppName[i] == '\'':
var chunkEnd = i-1 var chunkEnd = i-1
var idx, stars: int var idx, stars: int
if scanCppGenericSlot(cppName.data, i, idx, stars): if scanCppGenericSlot(cppName, i, idx, stars):
result.add cppName.data.substr(chunkStart, chunkEnd) result.add cppName.substr(chunkStart, chunkEnd)
chunkStart = i chunkStart = i
let typeInSlot = resolveStarsInCppType(origTyp, idx + 1, stars) let typeInSlot = resolveStarsInCppType(origTyp, idx + 1, stars)
@ -864,9 +859,9 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
inc i inc i
if chunkStart != 0: if chunkStart != 0:
result.add cppName.data.substr(chunkStart) result.add cppName.substr(chunkStart)
else: else:
result = cppName & "<" result = cppNameAsRope & "<"
for i in 1..<origTyp.len-1: for i in 1..<origTyp.len-1:
if i > 1: result.add(" COMMA ") if i > 1: result.add(" COMMA ")
addResultType(origTyp[i]) addResultType(origTyp[i])
@ -877,13 +872,13 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
# The resulting type will include commas and these won't play well # The resulting type will include commas and these won't play well
# with the C macros for defining procs such as N_NIMCALL. We must # with the C macros for defining procs such as N_NIMCALL. We must
# create a typedef for the type and use it in the proc signature: # create a typedef for the type and use it in the proc signature:
let typedefName = ~"TY" & $sig let typedefName = "TY" & $sig
m.s[cfsTypes].addf("typedef $1 $2;$n", [result, typedefName]) m.s[cfsTypes].addf("typedef $1 $2;$n", [result, typedefName])
m.typeCache[sig] = typedefName m.typeCache[sig] = typedefName
result = typedefName result = typedefName
else: else:
result = cacheGetType(m.forwTypeCache, sig) result = cacheGetType(m.forwTypeCache, sig)
if result == nil: if result == "":
result = getTypeName(m, origTyp, sig) result = getTypeName(m, origTyp, sig)
m.forwTypeCache[sig] = result m.forwTypeCache[sig] = result
if not isImportedType(t): if not isImportedType(t):
@ -899,7 +894,9 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
discard # addAbiCheck(m, t, result) # already handled elsewhere discard # addAbiCheck(m, t, result) # already handled elsewhere
of tySet: of tySet:
# Don't use the imported name as it may be scoped: 'Foo::SomeKind' # Don't use the imported name as it may be scoped: 'Foo::SomeKind'
result = $t.kind & '_' & t.lastSon.typeName & $t.lastSon.hashType result = rope("tySet_")
t.lastSon.typeName(result)
result.add $t.lastSon.hashType
m.typeCache[sig] = result m.typeCache[sig] = result
if not isImportedType(t): if not isImportedType(t):
let s = int(getSize(m.config, t)) let s = int(getSize(m.config, t))
@ -912,7 +909,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
result = getTypeDescAux(m, lastSon(t), check, kind) result = getTypeDescAux(m, lastSon(t), check, kind)
else: else:
internalError(m.config, "getTypeDescAux(" & $t.kind & ')') internalError(m.config, "getTypeDescAux(" & $t.kind & ')')
result = nil result = ""
# fixes bug #145: # fixes bug #145:
excl(check, t.id) excl(check, t.id)
@ -963,21 +960,12 @@ proc isReloadable(m: BModule, prc: PSym): bool =
proc isNonReloadable(m: BModule, prc: PSym): bool = proc isNonReloadable(m: BModule, prc: PSym): bool =
return m.hcrOn and sfNonReloadable in prc.flags return m.hcrOn and sfNonReloadable in prc.flags
proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope = proc genProcHeader(m: BModule, prc: PSym; result: var Rope; asPtr: bool = false) =
var
rettype, params: Rope
# using static is needed for inline procs # using static is needed for inline procs
if lfExportLib in prc.loc.flags:
if isHeaderFile in m.flags:
result.add "N_LIB_IMPORT "
else:
result.add "N_LIB_EXPORT "
elif prc.typ.callConv == ccInline or asPtr or isNonReloadable(m, prc):
result.add "static "
elif sfImportc notin prc.flags:
result.add "N_LIB_PRIVATE "
var check = initIntSet() var check = initIntSet()
fillLoc(prc.loc, locProc, prc.ast[namePos], mangleName(m, prc), OnUnknown) fillBackendName(m, prc)
fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown)
var rettype, params: Rope
genProcParams(m, prc.typ, rettype, params, check) genProcParams(m, prc.typ, rettype, params, check)
# handle the 2 options for hotcodereloading codegen - function pointer # handle the 2 options for hotcodereloading codegen - function pointer
# (instead of forward declaration) or header for function body with "_actual" postfix # (instead of forward declaration) or header for function body with "_actual" postfix
@ -988,12 +976,21 @@ proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope =
# careful here! don't access ``prc.ast`` as that could reload large parts of # careful here! don't access ``prc.ast`` as that could reload large parts of
# the object graph! # the object graph!
if prc.constraint.isNil: if prc.constraint.isNil:
if lfExportLib in prc.loc.flags:
if isHeaderFile in m.flags:
result.add "N_LIB_IMPORT "
else:
result.add "N_LIB_EXPORT "
elif prc.typ.callConv == ccInline or asPtr or isNonReloadable(m, prc):
result.add "static "
elif sfImportc notin prc.flags:
result.add "N_LIB_PRIVATE "
result.addf("$1$2($3, $4)$5", result.addf("$1$2($3, $4)$5",
[rope(CallingConvToStr[prc.typ.callConv]), asPtrStr, rettype, name, [rope(CallingConvToStr[prc.typ.callConv]), asPtrStr, rettype, name,
params]) params])
else: else:
let asPtrStr = if asPtr: (rope("(*") & name & ")") else: name let asPtrStr = if asPtr: (rope("(*") & name & ")") else: name
result = runtimeFormat(prc.cgDeclFrmt, [rettype, asPtrStr, params]) result.add runtimeFormat(prc.cgDeclFrmt, [rettype, asPtrStr, params])
# ------------------ type info generation ------------------------------------- # ------------------ type info generation -------------------------------------
@ -1032,7 +1029,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
#else echo("can contain a cycle: " & typeToString(typ)) #else echo("can contain a cycle: " & typeToString(typ))
if flags != 0: if flags != 0:
m.s[cfsTypeInit3].addf("$1.flags = $2;$n", [nameHcr, rope(flags)]) m.s[cfsTypeInit3].addf("$1.flags = $2;$n", [nameHcr, rope(flags)])
discard cgsym(m, "TNimType") cgsym(m, "TNimType")
if isDefined(m.config, "nimTypeNames"): if isDefined(m.config, "nimTypeNames"):
var typename = typeToString(if origType.typeInst != nil: origType.typeInst var typename = typeToString(if origType.typeInst != nil: origType.typeInst
else: origType, preferName) else: origType, preferName)
@ -1040,16 +1037,16 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
typename = "anon ref object from " & m.config$origType.skipTypes(skipPtrs).sym.info typename = "anon ref object from " & m.config$origType.skipTypes(skipPtrs).sym.info
m.s[cfsTypeInit3].addf("$1.name = $2;$n", m.s[cfsTypeInit3].addf("$1.name = $2;$n",
[nameHcr, makeCString typename]) [nameHcr, makeCString typename])
discard cgsym(m, "nimTypeRoot") cgsym(m, "nimTypeRoot")
m.s[cfsTypeInit3].addf("$1.nextType = nimTypeRoot; nimTypeRoot=&$1;$n", m.s[cfsTypeInit3].addf("$1.nextType = nimTypeRoot; nimTypeRoot=&$1;$n",
[nameHcr]) [nameHcr])
if m.hcrOn: if m.hcrOn:
m.s[cfsData].addf("static TNimType* $1;$n", [name]) m.s[cfsStrData].addf("static TNimType* $1;$n", [name])
m.hcrCreateTypeInfosProc.addf("\thcrRegisterGlobal($2, \"$1\", sizeof(TNimType), NULL, (void**)&$1);$n", m.hcrCreateTypeInfosProc.addf("\thcrRegisterGlobal($2, \"$1\", sizeof(TNimType), NULL, (void**)&$1);$n",
[name, getModuleDllPath(m, m.module)]) [name, getModuleDllPath(m, m.module)])
else: else:
m.s[cfsData].addf("N_LIB_PRIVATE TNimType $1;$n", [name]) m.s[cfsStrData].addf("N_LIB_PRIVATE TNimType $1;$n", [name])
proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope; proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope;
info: TLineInfo) = info: TLineInfo) =
@ -1077,7 +1074,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
proc rope(arg: Int128): Rope = rope($arg) proc rope(arg: Int128): Rope = rope($arg)
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope = proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
discard cgsym(m, "TNimNode") cgsym(m, "TNimNode")
var tmp = discriminatorTableName(m, objtype, d) var tmp = discriminatorTableName(m, objtype, d)
result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(m.config, d.typ)+1)] result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(m.config, d.typ)+1)]
@ -1112,7 +1109,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
var tmp = discriminatorTableName(m, typ, field) var tmp = discriminatorTableName(m, typ, field)
var L = lengthOrd(m.config, field.typ) var L = lengthOrd(m.config, field.typ)
assert L > 0 assert L > 0
if field.loc.r == nil: fillObjectFields(m, typ) if field.loc.r == "": fillObjectFields(m, typ)
if field.loc.t == nil: if field.loc.t == nil:
internalError(m.config, n.info, "genObjectFields") internalError(m.config, n.info, "genObjectFields")
m.s[cfsTypeInit3].addf("$1.kind = 3;$n" & m.s[cfsTypeInit3].addf("$1.kind = 3;$n" &
@ -1150,7 +1147,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
# Do not produce code for void types # Do not produce code for void types
if isEmptyType(field.typ): return if isEmptyType(field.typ): return
if field.bitsize == 0: if field.bitsize == 0:
if field.loc.r == nil: fillObjectFields(m, typ) if field.loc.r == "": fillObjectFields(m, typ)
if field.loc.t == nil: if field.loc.t == nil:
internalError(m.config, n.info, "genObjectFields") internalError(m.config, n.info, "genObjectFields")
m.s[cfsTypeInit3].addf("$1.kind = 1;$n" & m.s[cfsTypeInit3].addf("$1.kind = 1;$n" &
@ -1244,7 +1241,7 @@ proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
assert(typ[0] != nil) assert(typ[0] != nil)
genTypeInfoAux(m, typ, typ, name, info) genTypeInfoAux(m, typ, typ, name, info)
var tmp = getNimNode(m) var tmp = getNimNode(m)
m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n", m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 0;$n$3.node = &$1;$n",
[tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)]) [tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)])
proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
@ -1269,11 +1266,11 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
proc declareNimType(m: BModule, name: string; str: Rope, module: int) = proc declareNimType(m: BModule, name: string; str: Rope, module: int) =
let nr = rope(name) let nr = rope(name)
if m.hcrOn: if m.hcrOn:
m.s[cfsData].addf("static $2* $1;$n", [str, nr]) m.s[cfsStrData].addf("static $2* $1;$n", [str, nr])
m.s[cfsTypeInit1].addf("\t$1 = ($3*)hcrGetGlobal($2, \"$1\");$n", m.s[cfsTypeInit1].addf("\t$1 = ($3*)hcrGetGlobal($2, \"$1\");$n",
[str, getModuleDllPath(m, module), nr]) [str, getModuleDllPath(m, module), nr])
else: else:
m.s[cfsData].addf("extern $2 $1;$n", [str, nr]) m.s[cfsStrData].addf("extern $2 $1;$n", [str, nr])
proc genTypeInfo2Name(m: BModule; t: PType): Rope = proc genTypeInfo2Name(m: BModule; t: PType): Rope =
var res = "|" var res = "|"
@ -1300,7 +1297,7 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope =
proc isTrivialProc(g: ModuleGraph; s: PSym): bool {.inline.} = getBody(g, s).len == 0 proc isTrivialProc(g: ModuleGraph; s: PSym): bool {.inline.} = getBody(g, s).len == 0
proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope = proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp; result: var Rope) =
let theProc = getAttachedOp(m.g.graph, t, op) let theProc = getAttachedOp(m.g.graph, t, op)
if theProc != nil and not isTrivialProc(m.g.graph, theProc): if theProc != nil and not isTrivialProc(m.g.graph, theProc):
# the prototype of a destructor is ``=destroy(x: var T)`` and that of a # the prototype of a destructor is ``=destroy(x: var T)`` and that of a
@ -1311,7 +1308,7 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope =
theProc.name.s & " needs to have the 'nimcall' calling convention") theProc.name.s & " needs to have the 'nimcall' calling convention")
genProc(m, theProc) genProc(m, theProc)
result = theProc.loc.r result.add theProc.loc.r
when false: when false:
if not canFormAcycle(t) and op == attachedTrace: if not canFormAcycle(t) and op == attachedTrace:
@ -1323,7 +1320,7 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope =
# unfortunately this check is wrong for an object type that only contains # unfortunately this check is wrong for an object type that only contains
# .cursor fields like 'Node' inside 'cycleleak'. # .cursor fields like 'Node' inside 'cycleleak'.
internalError(m.config, info, "no attached trace proc found") internalError(m.config, info, "no attached trace proc found")
result = rope("NIM_NIL") result.add rope("NIM_NIL")
proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) = proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) =
var typeName: Rope var typeName: Rope
@ -1335,17 +1332,23 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn
else: else:
typeName = rope("NIM_NIL") typeName = rope("NIM_NIL")
discard cgsym(m, "TNimTypeV2") cgsym(m, "TNimTypeV2")
m.s[cfsData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name]) m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name])
let destroyImpl = genHook(m, t, info, attachedDestructor)
let traceImpl = genHook(m, t, info, attachedTrace)
var flags = 0 var flags = 0
if not canFormAcycle(t): flags = flags or 1 if not canFormAcycle(t): flags = flags or 1
addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.name = $4;$n; $1.traceImpl = (void*)$5; $1.flags = $6;", [ var typeEntry = newRopeAppender()
name, destroyImpl, getTypeDesc(m, t), typeName, addf(typeEntry, "$1.destructor = (void*)", [name])
traceImpl, rope(flags)]) genHook(m, t, info, attachedDestructor, typeEntry)
addf(typeEntry, "; $1.traceImpl = (void*)", [name])
genHook(m, t, info, attachedTrace, typeEntry)
addf(typeEntry, "; $1.name = $2;$n; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.flags = $4;",
[name, typeName, getTypeDesc(m, t), rope(flags)])
m.s[cfsTypeInit3].add typeEntry
if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
discard genTypeInfoV1(m, t, info) discard genTypeInfoV1(m, t, info)
@ -1359,12 +1362,12 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope =
let sig = hashType(origType) let sig = hashType(origType)
result = m.typeInfoMarkerV2.getOrDefault(sig) result = m.typeInfoMarkerV2.getOrDefault(sig)
if result != nil: if result != "":
return prefixTI.rope & result & ")".rope return prefixTI.rope & result & ")".rope
let marker = m.g.typeInfoMarkerV2.getOrDefault(sig) let marker = m.g.typeInfoMarkerV2.getOrDefault(sig)
if marker.str != nil: if marker.str != "":
discard cgsym(m, "TNimTypeV2") cgsym(m, "TNimTypeV2")
declareNimType(m, "TNimTypeV2", marker.str, marker.owner) declareNimType(m, "TNimTypeV2", marker.str, marker.owner)
# also store in local type section: # also store in local type section:
m.typeInfoMarkerV2[sig] = marker.str m.typeInfoMarkerV2[sig] = marker.str
@ -1378,7 +1381,7 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope =
# make sure the type info is created in the owner module # make sure the type info is created in the owner module
discard genTypeInfoV2(m.g.modules[owner], origType, info) discard genTypeInfoV2(m.g.modules[owner], origType, info)
# reference the type info as extern here # reference the type info as extern here
discard cgsym(m, "TNimTypeV2") cgsym(m, "TNimTypeV2")
declareNimType(m, "TNimTypeV2", result, owner) declareNimType(m, "TNimTypeV2", result, owner)
return prefixTI.rope & result & ")".rope return prefixTI.rope & result & ")".rope
@ -1430,13 +1433,13 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
let sig = hashType(origType) let sig = hashType(origType)
result = m.typeInfoMarker.getOrDefault(sig) result = m.typeInfoMarker.getOrDefault(sig)
if result != nil: if result != "":
return prefixTI.rope & result & ")".rope return prefixTI.rope & result & ")".rope
let marker = m.g.typeInfoMarker.getOrDefault(sig) let marker = m.g.typeInfoMarker.getOrDefault(sig)
if marker.str != nil: if marker.str != "":
discard cgsym(m, "TNimType") cgsym(m, "TNimType")
discard cgsym(m, "TNimNode") cgsym(m, "TNimNode")
declareNimType(m, "TNimType", marker.str, marker.owner) declareNimType(m, "TNimType", marker.str, marker.owner)
# also store in local type section: # also store in local type section:
m.typeInfoMarker[sig] = marker.str m.typeInfoMarker[sig] = marker.str
@ -1447,8 +1450,8 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
let old = m.g.graph.emittedTypeInfo.getOrDefault($result) let old = m.g.graph.emittedTypeInfo.getOrDefault($result)
if old != FileIndex(0): if old != FileIndex(0):
discard cgsym(m, "TNimType") cgsym(m, "TNimType")
discard cgsym(m, "TNimNode") cgsym(m, "TNimNode")
declareNimType(m, "TNimType", result, old.int) declareNimType(m, "TNimType", result, old.int)
return prefixTI.rope & result & ")".rope return prefixTI.rope & result & ")".rope
@ -1457,8 +1460,8 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
# make sure the type info is created in the owner module # make sure the type info is created in the owner module
discard genTypeInfoV1(m.g.modules[owner], origType, info) discard genTypeInfoV1(m.g.modules[owner], origType, info)
# reference the type info as extern here # reference the type info as extern here
discard cgsym(m, "TNimType") cgsym(m, "TNimType")
discard cgsym(m, "TNimNode") cgsym(m, "TNimNode")
declareNimType(m, "TNimType", result, owner) declareNimType(m, "TNimType", result, owner)
return prefixTI.rope & result & ")".rope return prefixTI.rope & result & ")".rope
else: else:

View file

@ -23,7 +23,7 @@ when defined(nimPreviewSlimSystem):
when not defined(leanCompiler): when not defined(leanCompiler):
import spawn, semparallel import spawn, semparallel
import strutils except `%` # collides with ropes.`%` import strutils except `%`, addf # collides with ropes.`%`
from ic / ic import ModuleBackendFlag from ic / ic import ModuleBackendFlag
import dynlib import dynlib
@ -63,16 +63,23 @@ proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) =
result.k = k result.k = k
result.storage = s result.storage = s
result.lode = lode result.lode = lode
result.r = nil result.r = ""
result.flags = {} result.flags = {}
proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) = proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) {.inline.} =
# fills the loc if it is not already initialized
if a.k == locNone:
a.k = k
a.lode = lode
a.storage = s
if a.r == "": a.r = r
proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) {.inline.} =
# 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.lode = lode a.lode = lode
a.storage = s a.storage = s
if a.r == nil: a.r = r
proc t(a: TLoc): PType {.inline.} = proc t(a: TLoc): PType {.inline.} =
if a.lode.kind == nkSym: if a.lode.kind == nkSym:
@ -96,7 +103,8 @@ proc useHeader(m: BModule, sym: PSym) =
let str = getStr(sym.annex.path) let str = getStr(sym.annex.path)
m.includeHeader(str) m.includeHeader(str)
proc cgsym(m: BModule, name: string): Rope proc cgsym(m: BModule, name: string)
proc cgsymValue(m: BModule, name: string): Rope
proc getCFile(m: BModule): AbsoluteFile proc getCFile(m: BModule): AbsoluteFile
@ -113,10 +121,6 @@ proc getModuleDllPath(m: BModule, s: PSym): Rope =
import macros import macros
proc cgFormatValue(result: var string; value: Rope) =
for str in leaves(value):
result.add str
proc cgFormatValue(result: var string; value: string) = proc cgFormatValue(result: var string; value: string) =
result.add value result.add value
@ -197,7 +201,7 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
var ident = newLit(substr(frmt, i, j-1)) var ident = newLit(substr(frmt, i, j-1))
i = j i = j
flushStrLit() flushStrLit()
result.add newCall(formatValue, resVar, newCall(ident"cgsym", m, ident)) result.add newCall(formatValue, resVar, newCall(ident"cgsymValue", m, ident))
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
@ -206,7 +210,7 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
inc(i) inc(i)
let ident = args[j-1] let ident = args[j-1]
flushStrLit() flushStrLit()
result.add newCall(formatValue, resVar, newCall(ident"cgsym", m, ident)) result.add newCall(formatValue, resVar, newCall(ident"cgsymValue", m, ident))
var start = i var start = i
while i < frmt.len: while i < frmt.len:
if frmt[i] != '$' and frmt[i] != '#': inc(i) if frmt[i] != '$' and frmt[i] != '#': inc(i)
@ -217,10 +221,9 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
flushStrLit() flushStrLit()
result.add newCall(ident"rope", resVar) result.add newCall(ident"rope", resVar)
proc indentLine(p: BProc, r: Rope): Rope = proc addIndent(p: BProc; result: var Rope) =
result = r
for i in 0..<p.blocks.len: for i in 0..<p.blocks.len:
prepend(result, "\t".rope) result.add "\t".rope
template appcg(m: BModule, c: var Rope, frmt: FormatStr, template appcg(m: BModule, c: var Rope, frmt: FormatStr,
args: untyped) = args: untyped) =
@ -234,23 +237,24 @@ template appcg(p: BProc, sec: TCProcSection, frmt: FormatStr,
args: untyped) = args: untyped) =
p.s(sec).add(ropecg(p.module, frmt, args)) p.s(sec).add(ropecg(p.module, frmt, args))
template line(p: BProc, sec: TCProcSection, r: Rope) =
p.s(sec).add(indentLine(p, r))
template line(p: BProc, sec: TCProcSection, r: string) = template line(p: BProc, sec: TCProcSection, r: string) =
p.s(sec).add(indentLine(p, r.rope)) addIndent p, p.s(sec)
p.s(sec).add(r)
template lineF(p: BProc, sec: TCProcSection, frmt: FormatStr, template lineF(p: BProc, sec: TCProcSection, frmt: FormatStr,
args: untyped) = args: untyped) =
p.s(sec).add(indentLine(p, frmt % args)) addIndent p, p.s(sec)
p.s(sec).add(frmt % args)
template lineCg(p: BProc, sec: TCProcSection, frmt: FormatStr, template lineCg(p: BProc, sec: TCProcSection, frmt: FormatStr,
args: untyped) = args: untyped) =
p.s(sec).add(indentLine(p, ropecg(p.module, frmt, args))) addIndent p, p.s(sec)
p.s(sec).add(ropecg(p.module, frmt, args))
template linefmt(p: BProc, sec: TCProcSection, frmt: FormatStr, template linefmt(p: BProc, sec: TCProcSection, frmt: FormatStr,
args: untyped) = args: untyped) =
p.s(sec).add(indentLine(p, ropecg(p.module, frmt, args))) addIndent p, p.s(sec)
p.s(sec).add(ropecg(p.module, frmt, args))
proc safeLineNm(info: TLineInfo): int = proc safeLineNm(info: TLineInfo): int =
result = toLinenumber(info) result = toLinenumber(info)
@ -276,7 +280,7 @@ proc genLineDir(p: BProc, t: PNode) =
let line = t.info.safeLineNm let line = t.info.safeLineNm
if optEmbedOrigSrc in p.config.globalOptions: if optEmbedOrigSrc in p.config.globalOptions:
p.s(cpsStmts).add(~"//" & sourceLine(p.config, t.info) & "\L") p.s(cpsStmts).add("//" & sourceLine(p.config, t.info) & "\L")
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config) genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config)
if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx: (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
@ -287,7 +291,7 @@ proc genLineDir(p: BProc, t: PNode) =
proc accessThreadLocalVar(p: BProc, s: PSym) proc accessThreadLocalVar(p: BProc, s: PSym)
proc emulatedThreadVars(conf: ConfigRef): bool {.inline.} proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
proc genProc(m: BModule, prc: PSym) proc genProc(m: BModule, prc: PSym)
proc raiseInstr(p: BProc): Rope proc raiseInstr(p: BProc; result: var Rope)
template compileToCpp(m: BModule): untyped = template compileToCpp(m: BModule): untyped =
m.config.backend == backendCpp or sfCompileToCpp in m.module.flags m.config.backend == backendCpp or sfCompileToCpp in m.module.flags
@ -298,10 +302,18 @@ proc getTempName(m: BModule): Rope =
proc rdLoc(a: TLoc): Rope = proc rdLoc(a: TLoc): Rope =
# 'read' location (deref if indirect) # 'read' location (deref if indirect)
result = a.r if lfIndirect in a.flags:
if lfIndirect in a.flags: result = "(*$1)" % [result] result = "(*" & a.r & ")"
else:
result = a.r
proc lenField(p: BProc): Rope = proc addRdLoc(a: TLoc; result: var Rope) =
if lfIndirect in a.flags:
result.add "(*" & a.r & ")"
else:
result.add a.r
proc lenField(p: BProc): Rope {.inline.} =
result = rope(if p.module.compileToCpp: "len" else: "Sup.len") result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
proc lenExpr(p: BProc; a: TLoc): Rope = proc lenExpr(p: BProc; a: TLoc): Rope =
@ -326,16 +338,24 @@ template mapTypeChooser(n: PNode): TSymKind =
template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode) template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode)
proc addrLoc(conf: ConfigRef; a: TLoc): Rope = proc addAddrLoc(conf: ConfigRef; a: TLoc; result: var Rope) =
result = a.r
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray: if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray:
result = "(&" & result & ")" result.add "(&" & a.r & ")"
else:
result.add a.r
proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray:
result = "(&" & a.r & ")"
else:
result = a.r
proc byRefLoc(p: BProc; a: TLoc): Rope = proc byRefLoc(p: BProc; a: TLoc): Rope =
result = a.r
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a)) != ctArray and not if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a)) != ctArray and not
p.module.compileToCpp: p.module.compileToCpp:
result = "(&" & result & ")" result = "(&" & a.r & ")"
else:
result = a.r
proc rdCharLoc(a: TLoc): Rope = proc rdCharLoc(a: TLoc): Rope =
# read a location that may need a char-cast: # read a location that may need a char-cast:
@ -416,7 +436,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
let typ = skipTypes(loc.t, abstractVarRange) let typ = skipTypes(loc.t, abstractVarRange)
if isImportedCppType(typ): return if isImportedCppType(typ): return
if optSeqDestructors in p.config.globalOptions and typ.kind in {tyString, tySequence}: if optSeqDestructors in p.config.globalOptions and typ.kind in {tyString, tySequence}:
assert rdLoc(loc) != nil assert loc.r != ""
let atyp = skipTypes(loc.t, abstractInst) let atyp = skipTypes(loc.t, abstractInst)
if atyp.kind in {tyVar, tyLent}: if atyp.kind in {tyVar, tyLent}:
@ -523,7 +543,8 @@ proc getIntTemp(p: BProc, result: var TLoc) =
proc localVarDecl(p: BProc; n: PNode): Rope = proc localVarDecl(p: BProc; n: PNode): Rope =
let s = n.sym let s = n.sym
if s.loc.k == locNone: if s.loc.k == locNone:
fillLoc(s.loc, locLocalVar, n, mangleLocalName(p, s), OnStack) fillLocalName(p, s)
fillLoc(s.loc, locLocalVar, n, OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
result.addf("NIM_ALIGN($1) ", [rope(s.alignment)]) result.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
@ -560,7 +581,8 @@ proc treatGlobalDifferentlyForHCR(m: BModule, s: PSym): bool =
proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
let s = n.sym let s = n.sym
if s.loc.k == locNone: if s.loc.k == locNone:
fillLoc(s.loc, locGlobalVar, n, mangleName(p.module, s), OnHeap) fillBackendName(p.module, s)
fillLoc(s.loc, locGlobalVar, n, OnHeap)
if treatGlobalDifferentlyForHCR(p.module, s): incl(s.loc.flags, lfIndirect) if treatGlobalDifferentlyForHCR(p.module, s): incl(s.loc.flags, lfIndirect)
if lfDynamicLib in s.loc.flags: if lfDynamicLib in s.loc.flags:
@ -569,7 +591,7 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
varInDynamicLib(q, s) varInDynamicLib(q, s)
else: else:
s.loc.r = mangleDynLibProc(s) s.loc.r = mangleDynLibProc(s)
if value != nil: if value != "":
internalError(p.config, n.info, ".dynlib variables cannot have a value") internalError(p.config, n.info, ".dynlib variables cannot have a value")
return return
useHeader(p.module, s) useHeader(p.module, s)
@ -577,10 +599,10 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
if not containsOrIncl(p.module.declaredThings, s.id): if not containsOrIncl(p.module.declaredThings, s.id):
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)
if value != nil: if value != "":
internalError(p.config, n.info, ".threadvar variables cannot have a value") internalError(p.config, n.info, ".threadvar variables cannot have a value")
else: else:
var decl: Rope = nil var decl: Rope = ""
var td = getTypeDesc(p.module, s.loc.t, skVar) var td = getTypeDesc(p.module, s.loc.t, skVar)
if s.constraint.isNil: if s.constraint.isNil:
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
@ -589,34 +611,35 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
elif sfImportc in s.flags: decl.add("extern ") elif sfImportc in s.flags: decl.add("extern ")
elif lfExportLib in s.loc.flags: decl.add("N_LIB_EXPORT_VAR ") elif lfExportLib in s.loc.flags: decl.add("N_LIB_EXPORT_VAR ")
else: decl.add("N_LIB_PRIVATE ") else: decl.add("N_LIB_PRIVATE ")
if s.kind == skLet and value != nil: decl.add("NIM_CONST ") if s.kind == skLet and value != "": decl.add("NIM_CONST ")
decl.add(td) decl.add(td)
if p.hcrOn: decl.add("*") if p.hcrOn: decl.add("*")
if sfRegister in s.flags: decl.add(" register") if sfRegister in s.flags: decl.add(" register")
if sfVolatile in s.flags: decl.add(" volatile") if sfVolatile in s.flags: decl.add(" volatile")
if sfNoalias in s.flags: decl.add(" NIM_NOALIAS") if sfNoalias in s.flags: decl.add(" NIM_NOALIAS")
if value != nil: if value != "":
decl.addf(" $1 = $2;$n", [s.loc.r, value]) decl.addf(" $1 = $2;$n", [s.loc.r, value])
else: else:
decl.addf(" $1;$n", [s.loc.r]) decl.addf(" $1;$n", [s.loc.r])
else: else:
if value != nil: if value != "":
decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value]) decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value])
else: else:
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r]) decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
p.module.s[cfsVars].add(decl) p.module.s[cfsVars].add(decl)
if p.withinLoop > 0 and value == nil: if p.withinLoop > 0 and value == "":
# fixes tests/run/tzeroarray: # fixes tests/run/tzeroarray:
resetLoc(p, s.loc) resetLoc(p, s.loc)
proc assignParam(p: BProc, s: PSym, retType: PType) = proc assignParam(p: BProc, s: PSym, retType: PType) =
assert(s.loc.r != nil) assert(s.loc.r != "")
scopeMangledParam(p, s) scopeMangledParam(p, s)
proc fillProcLoc(m: BModule; n: PNode) = proc fillProcLoc(m: BModule; n: PNode) =
let sym = n.sym let sym = n.sym
if sym.loc.k == locNone: if sym.loc.k == locNone:
fillLoc(sym.loc, locProc, n, mangleName(m, sym), OnStack) fillBackendName(m, sym)
fillLoc(sym.loc, locProc, n, OnStack)
proc getLabel(p: BProc): TLabel = proc getLabel(p: BProc): TLabel =
inc(p.labels) inc(p.labels)
@ -631,9 +654,9 @@ proc genStmts(p: BProc, t: PNode)
proc expr(p: BProc, n: PNode, d: var TLoc) proc expr(p: BProc, n: PNode, d: var TLoc)
proc genProcPrototype(m: BModule, sym: PSym) proc genProcPrototype(m: BModule, sym: PSym)
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
proc intLiteral(i: BiggestInt): Rope proc intLiteral(i: BiggestInt; result: var Rope)
proc genLiteral(p: BProc, n: PNode): Rope proc genLiteral(p: BProc, n: PNode; result: var Rope)
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
proc raiseExit(p: BProc) proc raiseExit(p: BProc)
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) = proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
@ -671,11 +694,11 @@ proc initFrame(p: BProc, procname, filename: Rope): Rope =
if p.module.s[cfsFrameDefines].len == 0: if p.module.s[cfsFrameDefines].len == 0:
appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"]) appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"])
discard cgsym(p.module, "nimFrame") cgsym(p.module, "nimFrame")
result = ropecg(p.module, "\tnimfr_($1, $2);$n", [procname, filename]) result = ropecg(p.module, "\tnimfr_($1, $2);$n", [procname, filename])
proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope = proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope =
discard cgsym(p.module, "nimFrame") cgsym(p.module, "nimFrame")
p.blocks[0].sections[cpsLocals].addf("TFrame $1;$n", [frame]) p.blocks[0].sections[cpsLocals].addf("TFrame $1;$n", [frame])
result = ropecg(p.module, "\t$1.procname = $2; $1.filename = $3; " & result = ropecg(p.module, "\t$1.procname = $2; $1.filename = $3; " &
" $1.line = $4; $1.len = -1; nimFrame(&$1);$n", " $1.line = $4; $1.len = -1; nimFrame(&$1);$n",
@ -702,24 +725,28 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
if not lib.generated: if not lib.generated:
lib.generated = true lib.generated = true
var tmp = getTempName(m) var tmp = getTempName(m)
assert(lib.name == nil) assert(lib.name == "")
lib.name = tmp # BUGFIX: cgsym has awful side-effects lib.name = tmp # BUGFIX: cgsym has awful side-effects
m.s[cfsVars].addf("static void* $1;$n", [tmp]) m.s[cfsVars].addf("static void* $1;$n", [tmp])
if lib.path.kind in {nkStrLit..nkTripleStrLit}: if lib.path.kind in {nkStrLit..nkTripleStrLit}:
var s: TStringSeq = @[] var s: TStringSeq = @[]
libCandidates(lib.path.strVal, s) libCandidates(lib.path.strVal, s)
rawMessage(m.config, hintDependency, lib.path.strVal) rawMessage(m.config, hintDependency, lib.path.strVal)
var loadlib: Rope = nil var loadlib: Rope = ""
for i in 0..high(s): for i in 0..high(s):
inc(m.labels) inc(m.labels)
if i > 0: loadlib.add("||") if i > 0: loadlib.add("||")
let n = newStrNode(nkStrLit, s[i]) let n = newStrNode(nkStrLit, s[i])
n.info = lib.path.info n.info = lib.path.info
appcg(m, loadlib, "($1 = #nimLoadLibrary($2))$n", appcg(m, loadlib, "($1 = #nimLoadLibrary(", [tmp])
[tmp, genStringLiteral(m, n)]) genStringLiteral(m, n, loadlib)
loadlib.addf "))$n", []
appcg(m, m.s[cfsDynLibInit], appcg(m, m.s[cfsDynLibInit],
"if (!($1)) #nimLoadLibraryError($2);$n", "if (!($1)) #nimLoadLibraryError(",
[loadlib, genStringLiteral(m, lib.path)]) [loadlib])
genStringLiteral(m, lib.path, m.s[cfsDynLibInit])
m.s[cfsDynLibInit].addf ");$n", []
else: else:
var p = newProc(nil, m) var p = newProc(nil, m)
p.options.excl optStackTrace p.options.excl optStackTrace
@ -738,7 +765,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
"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(m.config, "loadDynamicLib") if lib.name == "": internalError(m.config, "loadDynamicLib")
proc mangleDynLibProc(sym: PSym): Rope = proc mangleDynLibProc(sym: PSym): Rope =
# we have to build this as a single rope in order not to trip the # we have to build this as a single rope in order not to trip the
@ -803,18 +830,25 @@ 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): Rope = proc cgsymImpl(m: BModule; sym: PSym) {.inline.} =
case sym.kind
of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym)
of skVar, skResult, skLet: genVarPrototype(m, newSymNode sym)
of skType: discard getTypeDesc(m, sym.typ)
else: internalError(m.config, "cgsym: " & $sym.kind)
proc cgsym(m: BModule, name: string) =
let sym = magicsys.getCompilerProc(m.g.graph, name) let sym = magicsys.getCompilerProc(m.g.graph, name)
if sym != nil: if sym != nil:
case sym.kind cgsymImpl m, sym
of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym) else:
of skVar, skResult, skLet: genVarPrototype(m, newSymNode sym) rawMessage(m.config, errGenerated, "system module needs: " & name)
of skType: discard getTypeDesc(m, sym.typ)
else: internalError(m.config, "cgsym: " & name & ": " & $sym.kind) proc cgsymValue(m: BModule, name: string): Rope =
let sym = magicsys.getCompilerProc(m.g.graph, name)
if sym != nil:
cgsymImpl m, sym
else: else:
# we used to exclude the system module from this check, but for DLL
# generation support this sloppyness leads to hard to detect bugs, so
# we're picky here for the system module too:
rawMessage(m.config, errGenerated, "system module needs: " & name) rawMessage(m.config, errGenerated, "system module needs: " & name)
result = sym.loc.r result = sym.loc.r
if m.hcrOn and sym != nil and sym.kind in {skProc..skIterator}: if m.hcrOn and sym != nil and sym.kind in {skProc..skIterator}:
@ -845,12 +879,12 @@ proc generateHeaders(m: BModule) =
#undef unix #undef unix
""") """)
proc openNamespaceNim(namespace: string): Rope = proc openNamespaceNim(namespace: string; result: var Rope) =
result.add("namespace ") result.add("namespace ")
result.add(namespace) result.add(namespace)
result.add(" {\L") result.add(" {\L")
proc closeNamespaceNim(): Rope = proc closeNamespaceNim(result: var Rope) =
result.add("}\L") result.add("}\L")
proc closureSetup(p: BProc, prc: PSym) = proc closureSetup(p: BProc, prc: PSym) =
@ -1028,8 +1062,9 @@ proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
proc genProcAux(m: BModule, prc: PSym) = proc genProcAux(m: BModule, prc: PSym) =
var p = newProc(prc, m) var p = newProc(prc, m)
var header = genProcHeader(m, prc) var header = newRopeAppender()
var returnStmt: Rope = nil genProcHeader(m, prc, header)
var returnStmt: Rope = ""
assert(prc.ast != nil) assert(prc.ast != nil)
var procBody = transformBody(m.g.graph, m.idgen, prc, cache = false) var procBody = transformBody(m.g.graph, m.idgen, prc, cache = false)
@ -1051,7 +1086,7 @@ proc genProcAux(m: BModule, prc: PSym) =
else: else:
# declare the result symbol: # declare the result symbol:
assignLocalVar(p, resNode) assignLocalVar(p, resNode)
assert(res.loc.r != nil) assert(res.loc.r != "")
initLocalVar(p, res, immediateAsgn=false) initLocalVar(p, res, immediateAsgn=false)
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)]) returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
else: else:
@ -1109,10 +1144,10 @@ proc genProcAux(m: BModule, prc: PSym) =
if beforeRetNeeded in p.flags: generatedProc.add("{") if beforeRetNeeded in p.flags: generatedProc.add("{")
generatedProc.add(p.s(cpsInit)) generatedProc.add(p.s(cpsInit))
generatedProc.add(p.s(cpsStmts)) generatedProc.add(p.s(cpsStmts))
if beforeRetNeeded in p.flags: generatedProc.add(~"\t}BeforeRet_: ;$n") if beforeRetNeeded in p.flags: generatedProc.add("\t}BeforeRet_: ;\n")
if optStackTrace in prc.options: generatedProc.add(deinitFrame(p)) if optStackTrace in prc.options: generatedProc.add(deinitFrame(p))
generatedProc.add(returnStmt) generatedProc.add(returnStmt)
generatedProc.add(~"}$N") generatedProc.add("}\n")
m.s[cfsProcs].add(generatedProc) m.s[cfsProcs].add(generatedProc)
if isReloadable(m, prc): if isReloadable(m, prc):
m.s[cfsDynLibInit].addf("\t$1 = ($3) hcrRegisterProc($4, \"$1\", (void*)$2);$n", m.s[cfsDynLibInit].addf("\t$1 = ($3) hcrRegisterProc($4, \"$1\", (void*)$2);$n",
@ -1141,7 +1176,8 @@ proc genProcPrototype(m: BModule, sym: PSym) =
[mangleDynLibProc(sym), getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)]) [mangleDynLibProc(sym), getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)])
elif not containsOrIncl(m.declaredProtos, sym.id): elif not containsOrIncl(m.declaredProtos, sym.id):
let asPtr = isReloadable(m, sym) let asPtr = isReloadable(m, sym)
var header = genProcHeader(m, sym, asPtr) var header = newRopeAppender()
genProcHeader(m, sym, header, asPtr)
if not asPtr: if not asPtr:
if isNoReturn(m, sym) and hasDeclspec in extccomp.CC[m.config.cCompiler].props: if isNoReturn(m, sym) and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
header = "__declspec(noreturn) " & header header = "__declspec(noreturn) " & header
@ -1159,7 +1195,7 @@ proc genProcNoForward(m: BModule, prc: PSym) =
fillProcLoc(m, prc.ast[namePos]) fillProcLoc(m, prc.ast[namePos])
useHeader(m, prc) useHeader(m, prc)
# dependency to a compilerproc: # dependency to a compilerproc:
discard cgsym(m, prc.name.s) cgsym(m, prc.name.s)
return return
if lfNoDecl in prc.loc.flags: if lfNoDecl in prc.loc.flags:
fillProcLoc(m, prc.ast[namePos]) fillProcLoc(m, prc.ast[namePos])
@ -1250,14 +1286,15 @@ proc genVarPrototype(m: BModule, n: PNode) =
#assert(sfGlobal in sym.flags) #assert(sfGlobal in sym.flags)
let sym = n.sym let sym = n.sym
useHeader(m, sym) useHeader(m, sym)
fillLoc(sym.loc, locGlobalVar, n, mangleName(m, sym), OnHeap) fillBackendName(m, sym)
fillLoc(sym.loc, locGlobalVar, n, OnHeap)
if treatGlobalDifferentlyForHCR(m, sym): incl(sym.loc.flags, lfIndirect) if treatGlobalDifferentlyForHCR(m, sym): incl(sym.loc.flags, lfIndirect)
if (lfNoDecl in sym.loc.flags) or contains(m.declaredThings, sym.id): if (lfNoDecl in sym.loc.flags) or contains(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 != "")
if sfThread in sym.flags: if sfThread in sym.flags:
declareThreadVar(m, sym, true) declareThreadVar(m, sym, true)
else: else:
@ -1343,9 +1380,11 @@ proc genMainProc(m: BModule) =
assert prc != nil assert prc != nil
let n = newStrNode(nkStrLit, prc.annex.path.strVal) let n = newStrNode(nkStrLit, prc.annex.path.strVal)
n.info = prc.annex.path.info n.info = prc.annex.path.info
var strLit = newRopeAppender()
genStringLiteral(m, n, strLit)
appcg(m, result, "\tif (!($1 = #nimLoadLibrary($2)))$N" & appcg(m, result, "\tif (!($1 = #nimLoadLibrary($2)))$N" &
"\t\t#nimLoadLibraryError($2);$N", "\t\t#nimLoadLibraryError($2);$N",
[handle, genStringLiteral(m, n)]) [handle, strLit])
preMainCode.add(loadLib("hcr_handle", "hcrGetProc")) preMainCode.add(loadLib("hcr_handle", "hcrGetProc"))
preMainCode.add("\tvoid* rtl_handle;\L") preMainCode.add("\tvoid* rtl_handle;\L")
@ -1526,7 +1565,8 @@ proc genMainProc(m: BModule) =
if optNoMain notin m.config.globalOptions: if optNoMain notin m.config.globalOptions:
if m.config.cppCustomNamespace.len > 0: if m.config.cppCustomNamespace.len > 0:
m.s[cfsProcs].add closeNamespaceNim() & "using namespace " & m.config.cppCustomNamespace & ";\L" closeNamespaceNim(m.s[cfsProcs])
m.s[cfsProcs].add "using namespace " & m.config.cppCustomNamespace & ";\L"
if m.config.target.targetOS == osWindows and if m.config.target.targetOS == osWindows and
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
@ -1550,7 +1590,7 @@ proc genMainProc(m: BModule) =
appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix]) appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix])
if m.config.cppCustomNamespace.len > 0: if m.config.cppCustomNamespace.len > 0:
m.s[cfsProcs].add openNamespaceNim(m.config.cppCustomNamespace) openNamespaceNim(m.config.cppCustomNamespace, m.s[cfsProcs])
proc registerInitProcs*(g: BModuleList; m: PSym; flags: set[ModuleBackendFlag]) = proc registerInitProcs*(g: BModuleList; m: PSym; flags: set[ModuleBackendFlag]) =
## Called from the IC backend. ## Called from the IC backend.
@ -1733,7 +1773,7 @@ proc genInitCode(m: BModule) =
# Give this small function its own scope # Give this small function its own scope
prc.addf("{$N", []) prc.addf("{$N", [])
# Keep a bogus frame in case the code needs one # Keep a bogus frame in case the code needs one
prc.add(~"\tTFrame FR_; FR_.len = 0;$N") prc.add("\tTFrame FR_; FR_.len = 0;\n")
writeSection(preInitProc, cpsLocals) writeSection(preInitProc, cpsLocals)
writeSection(preInitProc, cpsInit, m.hcrOn) writeSection(preInitProc, cpsInit, m.hcrOn)
@ -1759,13 +1799,13 @@ proc genInitCode(m: BModule) =
var procname = makeCString(m.module.name.s) var procname = makeCString(m.module.name.s)
prc.add(initFrame(m.initProc, procname, quotedFilename(m.config, m.module.info))) prc.add(initFrame(m.initProc, procname, quotedFilename(m.config, m.module.info)))
else: else:
prc.add(~"\tTFrame FR_; FR_.len = 0;$N") prc.add("\tTFrame FR_; FR_.len = 0;\n")
writeSection(initProc, cpsInit, m.hcrOn) writeSection(initProc, cpsInit, m.hcrOn)
writeSection(initProc, cpsStmts) writeSection(initProc, cpsStmts)
if beforeRetNeeded in m.initProc.flags: if beforeRetNeeded in m.initProc.flags:
prc.add(~"\tBeforeRet_: ;$n") prc.add("\tBeforeRet_: ;\n")
if sfMainModule in m.module.flags and m.config.exc == excGoto: if sfMainModule in m.module.flags and m.config.exc == excGoto:
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil: if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
@ -1796,7 +1836,7 @@ proc genInitCode(m: BModule) =
m.s[cfsInitProc].addf("}$N$N", []) m.s[cfsInitProc].addf("}$N$N", [])
for i, el in pairs(m.extensionLoaders): for i, el in pairs(m.extensionLoaders):
if el != nil: if el != "":
let ex = "NIM_EXTERNC N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N" % let ex = "NIM_EXTERNC N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N" %
[(i.ord - '0'.ord).rope, el] [(i.ord - '0'.ord).rope, el]
moduleInitRequired = true moduleInitRequired = true
@ -1824,7 +1864,7 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
generateHeaders(m) generateHeaders(m)
result.add(m.s[cfsHeaders]) result.add(m.s[cfsHeaders])
if m.config.cppCustomNamespace.len > 0: if m.config.cppCustomNamespace.len > 0:
result.add openNamespaceNim(m.config.cppCustomNamespace) openNamespaceNim(m.config.cppCustomNamespace, result)
if m.s[cfsFrameDefines].len > 0: if m.s[cfsFrameDefines].len > 0:
result.add(m.s[cfsFrameDefines]) result.add(m.s[cfsFrameDefines])
else: else:
@ -1843,10 +1883,10 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
result.add(m.s[cfsDatInitProc]) result.add(m.s[cfsDatInitProc])
if m.config.cppCustomNamespace.len > 0: if m.config.cppCustomNamespace.len > 0:
result.add closeNamespaceNim() closeNamespaceNim(result)
if moduleIsEmpty: if moduleIsEmpty:
result = nil result = ""
proc initProcOptions(m: BModule): TOptions = proc initProcOptions(m: BModule): TOptions =
let opts = m.config.options let opts = m.config.options
@ -1867,6 +1907,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
result.typeInfoMarker = initTable[SigHash, Rope]() result.typeInfoMarker = initTable[SigHash, Rope]()
result.sigConflicts = initCountTable[SigHash]() result.sigConflicts = initCountTable[SigHash]()
result.initProc = newProc(nil, result) result.initProc = newProc(nil, result)
for i in low(result.s)..high(result.s): result.s[i] = newRopeAppender()
result.initProc.options = initProcOptions(result) result.initProc.options = initProcOptions(result)
result.preInitProc = newProc(nil, result) result.preInitProc = newProc(nil, result)
result.preInitProc.flags.incl nimErrorFlagDisabled result.preInitProc.flags.incl nimErrorFlagDisabled
@ -1924,13 +1965,14 @@ proc writeHeader(m: BModule) =
generateThreadLocalStorage(m) generateThreadLocalStorage(m)
for i in cfsHeaders..cfsProcs: for i in cfsHeaders..cfsProcs:
result.add(m.s[i]) result.add(m.s[i])
if m.config.cppCustomNamespace.len > 0 and i == cfsHeaders: result.add openNamespaceNim(m.config.cppCustomNamespace) if m.config.cppCustomNamespace.len > 0 and i == cfsHeaders:
openNamespaceNim(m.config.cppCustomNamespace, result)
result.add(m.s[cfsInitProc]) result.add(m.s[cfsInitProc])
if optGenDynLib in m.config.globalOptions: if optGenDynLib in m.config.globalOptions:
result.add("N_LIB_IMPORT ") result.add("N_LIB_IMPORT ")
result.addf("N_CDECL(void, $1NimMain)(void);$n", [rope m.config.nimMainPrefix]) result.addf("N_CDECL(void, $1NimMain)(void);$n", [rope m.config.nimMainPrefix])
if m.config.cppCustomNamespace.len > 0: result.add closeNamespaceNim() if m.config.cppCustomNamespace.len > 0: closeNamespaceNim(result)
result.addf("#endif /* $1 */$n", [guard]) result.addf("#endif /* $1 */$n", [guard])
if not writeRope(result, m.filename): if not writeRope(result, m.filename):
rawMessage(m.config, errCannotOpenFile, m.filename.string) rawMessage(m.config, errCannotOpenFile, m.filename.string)
@ -2034,7 +2076,7 @@ proc writeModule(m: BModule, pending: bool) =
var cf = Cfile(nimname: m.module.name.s, cname: cfile, var cf = Cfile(nimname: m.module.name.s, cname: cfile,
obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {})
var code = genModule(m, cf) var code = genModule(m, cf)
if code != nil or m.config.symbolFiles != disabledSf: if code != "" or m.config.symbolFiles != disabledSf:
when hasTinyCBackend: when hasTinyCBackend:
if m.config.cmd == cmdTcc: if m.config.cmd == cmdTcc:
tccgen.compileCCode($code, m.config) tccgen.compileCCode($code, m.config)
@ -2060,7 +2102,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
# phase ordering problem here: We need to announce this # phase ordering problem here: We need to announce this
# dependency to 'nimTestErrorFlag' before system.c has been written to disk. # dependency to 'nimTestErrorFlag' before system.c has been written to disk.
if m.config.exc == excGoto and getCompilerProc(graph, "nimTestErrorFlag") != nil: if m.config.exc == excGoto and getCompilerProc(graph, "nimTestErrorFlag") != nil:
discard cgsym(m, "nimTestErrorFlag") cgsym(m, "nimTestErrorFlag")
if {optGenStaticLib, optGenDynLib, optNoMain} * m.config.globalOptions == {}: if {optGenStaticLib, optGenDynLib, optNoMain} * m.config.globalOptions == {}:
for i in countdown(high(graph.globalDestructors), 0): for i in countdown(high(graph.globalDestructors), 0):
@ -2076,7 +2118,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
if m.hcrOn: if m.hcrOn:
# make sure this is pulled in (meaning hcrGetGlobal() is called for it during init) # make sure this is pulled in (meaning hcrGetGlobal() is called for it during init)
discard cgsym(m, "programResult") cgsym(m, "programResult")
if m.inHcrInitGuard: if m.inHcrInitGuard:
endBlock(m.initProc) endBlock(m.initProc)
@ -2086,17 +2128,17 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
# so it can load the HCR runtime and later pass the library handle to the HCR runtime which # so it can load the HCR runtime and later pass the library handle to the HCR runtime which
# will in turn pass it to the other modules it initializes so they can initialize the # will in turn pass it to the other modules it initializes so they can initialize the
# register/get procs so they don't have to have the definitions of these functions as well # register/get procs so they don't have to have the definitions of these functions as well
discard cgsym(m, "nimLoadLibrary") cgsym(m, "nimLoadLibrary")
discard cgsym(m, "nimLoadLibraryError") cgsym(m, "nimLoadLibraryError")
discard cgsym(m, "nimGetProcAddr") cgsym(m, "nimGetProcAddr")
discard cgsym(m, "procAddrError") cgsym(m, "procAddrError")
discard cgsym(m, "rawWrite") cgsym(m, "rawWrite")
# raise dependencies on behalf of genMainProc # raise dependencies on behalf of genMainProc
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}: if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
discard cgsym(m, "initStackBottomWith") cgsym(m, "initStackBottomWith")
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone: if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
discard cgsym(m, "initThreadVarsEmulation") cgsym(m, "initThreadVarsEmulation")
if m.g.forwardedProcs.len == 0: if m.g.forwardedProcs.len == 0:
incl m.flags, objHasKidsValid incl m.flags, objHasKidsValid

View file

@ -27,6 +27,7 @@ type
cfsFieldInfo, # section for field information cfsFieldInfo, # section for field information
cfsTypeInfo, # section for type information (ag ABI checks) cfsTypeInfo, # section for type information (ag ABI checks)
cfsProcHeaders, # section for C procs prototypes cfsProcHeaders, # section for C procs prototypes
cfsStrData, # section for constant string literals
cfsData, # section for C constant data cfsData, # section for C constant data
cfsVars, # section for C variable declarations cfsVars, # section for C variable declarations
cfsProcs, # section for C procs that are not inline cfsProcs, # section for C procs that are not inline
@ -190,13 +191,18 @@ proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
# top level proc sections # top level proc sections
result = p.blocks[0].sections[s] result = p.blocks[0].sections[s]
proc initBlock*(): TBlock =
result = TBlock()
for i in low(result.sections)..high(result.sections):
result.sections[i] = newRopeAppender()
proc newProc*(prc: PSym, module: BModule): BProc = proc newProc*(prc: PSym, module: BModule): BProc =
new(result) new(result)
result.prc = prc result.prc = prc
result.module = module result.module = module
result.options = if prc != nil: prc.options result.options = if prc != nil: prc.options
else: module.config.options else: module.config.options
newSeq(result.blocks, 1) result.blocks = @[initBlock()]
result.nestedTryStmts = @[] result.nestedTryStmts = @[]
result.finallySafePoints = @[] result.finallySafePoints = @[]
result.sigConflicts = initCountTable[string]() result.sigConflicts = initCountTable[string]()

View file

@ -123,7 +123,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
if disp.typ.callConv == ccInline: disp.typ.callConv = ccNimCall if disp.typ.callConv == ccInline: disp.typ.callConv = ccNimCall
disp.ast = copyTree(s.ast) disp.ast = copyTree(s.ast)
disp.ast[bodyPos] = newNodeI(nkEmpty, s.info) disp.ast[bodyPos] = newNodeI(nkEmpty, s.info)
disp.loc.r = nil disp.loc.r = ""
if s.typ[0] != nil: if s.typ[0] != nil:
if disp.ast.len > resultPos: if disp.ast.len > resultPos:
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, nextSymId(idgen)) disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, nextSymId(idgen))

View file

@ -13,7 +13,8 @@ import options, ast, ropes, passes, pathutils, msgs, lineinfos
import modulegraphs import modulegraphs
import std/[os, strutils, parseutils] import std/[os, parseutils]
import strutils except addf
import std/private/globs import std/private/globs
when defined(nimPreviewSlimSystem): when defined(nimPreviewSlimSystem):
@ -109,7 +110,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext
g.config = graph.config g.config = graph.config
g.graph = graph g.graph = graph
if graph.backend == nil: if graph.backend == nil:
graph.backend = Backend(dotGraph: nil) graph.backend = Backend(dotGraph: "")
result = g result = g
const gendependPass* = makePass(open = myOpen, process = addDotDependency) const gendependPass* = makePass(open = myOpen, process = addDotDependency)

View file

@ -14,7 +14,9 @@
import ropes, platform, condsyms, options, msgs, lineinfos, pathutils, modulepaths import ropes, platform, condsyms, options, msgs, lineinfos, pathutils, modulepaths
import std/[os, strutils, osproc, sha1, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils] import std/[os, osproc, sha1, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils]
import std / strutils except addf
when defined(nimPreviewSlimSystem): when defined(nimPreviewSlimSystem):
import std/syncio import std/syncio
@ -616,7 +618,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
"for the selected C compiler: " & CC[conf.cCompiler].name) "for the selected C compiler: " & CC[conf.cCompiler].name)
result.add(' ') result.add(' ')
result.addf(CC[c].compileTmpl, [ strutils.addf(result, CC[c].compileTmpl, [
"dfile", dfile, "dfile", dfile,
"file", cfsh, "objfile", quoteShell(objfile), "file", cfsh, "objfile", quoteShell(objfile),
"options", options, "include", includeCmd, "options", options, "include", includeCmd,
@ -707,7 +709,7 @@ proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile,
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
"exefile", exefile, "nim", getPrefixDir(conf).string, "lib", conf.libpath.string]) "exefile", exefile, "nim", getPrefixDir(conf).string, "lib", conf.libpath.string])
result.add ' ' result.add ' '
result.addf(linkTmpl, ["builddll", builddll, strutils.addf(result, linkTmpl, ["builddll", builddll,
"mapfile", mapfile, "mapfile", mapfile,
"buildgui", buildgui, "options", linkOptions, "buildgui", buildgui, "options", linkOptions,
"objfiles", objfiles, "exefile", exefile, "objfiles", objfiles, "exefile", exefile,
@ -856,7 +858,7 @@ proc callCCompiler*(conf: ConfigRef) =
return # speed up that call if only compiling and no script shall be return # speed up that call if only compiling and no script shall be
# generated # generated
#var c = cCompiler #var c = cCompiler
var script: Rope = nil var script: Rope = ""
var cmds: TStringSeq var cmds: TStringSeq
var prettyCmds: TStringSeq var prettyCmds: TStringSeq
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx]) let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])

View file

@ -403,7 +403,7 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
p.bitsize = s.bitsize p.bitsize = s.bitsize
p.alignment = s.alignment p.alignment = s.alignment
p.externalName = toLitId(if s.loc.r.isNil: "" else: $s.loc.r, m) p.externalName = toLitId(s.loc.r, m)
p.locFlags = s.loc.flags p.locFlags = s.loc.flags
c.addMissing s.typ c.addMissing s.typ
p.typ = s.typ.storeType(c, m) p.typ = s.typ.storeType(c, m)

View file

@ -35,7 +35,8 @@ import
cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
transf, injectdestructors, sourcemap, astmsgs transf, injectdestructors, sourcemap, astmsgs
import json, sets, math, tables, intsets, strutils import json, sets, math, tables, intsets
import strutils except addf
when defined(nimPreviewSlimSystem): when defined(nimPreviewSlimSystem):
import std/[assertions, syncio] import std/[assertions, syncio]
@ -110,21 +111,18 @@ type
template config*(p: PProc): ConfigRef = p.module.config template config*(p: PProc): ConfigRef = p.module.config
proc indentLine(p: PProc, r: Rope): Rope = proc indentLine(p: PProc, r: Rope): Rope =
result = r
var p = p var p = p
var ind = 0
while true: while true:
for i in 0..<p.blocks.len + p.extraIndent: inc ind, p.blocks.len + p.extraIndent
prepend(result, rope" ")
if p.up == nil or p.up.prc != p.prc.owner: if p.up == nil or p.up.prc != p.prc.owner:
break break
p = p.up p = p.up
result = repeat(' ', ind*2) & r
template line(p: PProc, added: string) = template line(p: PProc, added: string) =
p.body.add(indentLine(p, rope(added))) p.body.add(indentLine(p, rope(added)))
template line(p: PProc, added: Rope) =
p.body.add(indentLine(p, added))
template lineF(p: PProc, frmt: FormatStr, args: varargs[Rope]) = template lineF(p: PProc, frmt: FormatStr, args: varargs[Rope]) =
p.body.add(indentLine(p, ropes.`%`(frmt, args))) p.body.add(indentLine(p, ropes.`%`(frmt, args)))
@ -140,9 +138,9 @@ proc newGlobals(): PGlobals =
result.typeInfoGenerated = initIntSet() result.typeInfoGenerated = initIntSet()
proc initCompRes(r: var TCompRes) = proc initCompRes(r: var TCompRes) =
r.address = nil r.address = ""
r.res = nil r.res = ""
r.tmpLoc = nil r.tmpLoc = ""
r.typ = etyNone r.typ = etyNone
r.kind = resNone r.kind = resNone
@ -241,7 +239,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
if chr notin {'A'..'Z','a'..'z','_','$','0'..'9'}: if chr notin {'A'..'Z','a'..'z','_','$','0'..'9'}:
return false return false
result = s.loc.r result = s.loc.r
if result == nil: if result == "":
if s.kind == skField and s.name.s.validJsName: if s.kind == skField and s.name.s.validJsName:
result = rope(s.name.s) result = rope(s.name.s)
elif s.kind == skTemp: elif s.kind == skTemp:
@ -464,7 +462,7 @@ proc maybeMakeTemp(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rope] =
b = a b = a
if needsTemp(p, n): if needsTemp(p, n):
# if we have tmp just use it # if we have tmp just use it
if x.tmpLoc != nil and (mapType(n.typ) == etyBaseIndex or n.kind in {nkHiddenDeref, nkDerefExpr}): if x.tmpLoc != "" and (mapType(n.typ) == etyBaseIndex or n.kind in {nkHiddenDeref, nkDerefExpr}):
b = "$1[0][$1[1]]" % [x.tmpLoc] b = "$1[0][$1[1]]" % [x.tmpLoc]
(a: a, tmp: b) (a: a, tmp: b)
else: else:
@ -481,10 +479,10 @@ proc maybeMakeTempAssignable(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rop
b = a b = a
if needsTemp(p, n): if needsTemp(p, n):
# if we have tmp just use it # if we have tmp just use it
if x.tmpLoc != nil and (mapType(n.typ) == etyBaseIndex or n.kind in {nkHiddenDeref, nkDerefExpr}): if x.tmpLoc != "" and (mapType(n.typ) == etyBaseIndex or n.kind in {nkHiddenDeref, nkDerefExpr}):
b = "$1[0][$1[1]]" % [x.tmpLoc] b = "$1[0][$1[1]]" % [x.tmpLoc]
result = (a: a, tmp: b) result = (a: a, tmp: b)
elif x.tmpLoc != nil and n.kind == nkBracketExpr: elif x.tmpLoc != "" and n.kind == nkBracketExpr:
# genArrayAddr # genArrayAddr
var var
address, index: TCompRes address, index: TCompRes
@ -745,7 +743,7 @@ proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
else: else:
lineF(p, "$1;$n", [src.rdLoc]) lineF(p, "$1;$n", [src.rdLoc])
src.kind = resNone src.kind = resNone
src.res = nil src.res = ""
proc genTry(p: PProc, n: PNode, r: var TCompRes) = proc genTry(p: PProc, n: PNode, r: var TCompRes) =
# code to generate: # code to generate:
@ -800,7 +798,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
moveInto(p, a, r) moveInto(p, a, r)
if i > 1: lineF(p, "}$n", []) if i > 1: lineF(p, "}$n", [])
else: else:
var orExpr: Rope = nil var orExpr: Rope = ""
var excAlias: PNode = nil var excAlias: PNode = nil
useMagic(p, "isObj") useMagic(p, "isObj")
@ -813,13 +811,13 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
excAlias = it[2] excAlias = it[2]
# If this is a ``except exc as sym`` branch there must be no following # If this is a ``except exc as sym`` branch there must be no following
# nodes # nodes
doAssert orExpr == nil doAssert orExpr == ""
elif it.kind == nkType: elif it.kind == nkType:
throwObj = it throwObj = it
else: else:
internalError(p.config, n.info, "genTryStmt") internalError(p.config, n.info, "genTryStmt")
if orExpr != nil: orExpr.add("||") if orExpr != "": orExpr.add("||")
# Generate the correct type checking code depending on whether this is a # Generate the correct type checking code depending on whether this is a
# NIM-native or a JS-native exception # NIM-native or a JS-native exception
# if isJsObject(throwObj.typ): # if isJsObject(throwObj.typ):
@ -907,7 +905,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
gen(p, e[1], b) gen(p, e[1], b)
if j != itLen - 2: if j != itLen - 2:
lineF(p, "$1 >= $2 && $1 <= $3 || $n", [cond.rdLoc, a.rdLoc, b.rdLoc]) lineF(p, "$1 >= $2 && $1 <= $3 || $n", [cond.rdLoc, a.rdLoc, b.rdLoc])
else: else:
lineF(p, "$1 >= $2 && $1 <= $3", [cond.rdLoc, a.rdLoc, b.rdLoc]) lineF(p, "$1 >= $2 && $1 <= $3", [cond.rdLoc, a.rdLoc, b.rdLoc])
else: else:
var v = copyNode(e[0]) var v = copyNode(e[0])
@ -998,7 +996,7 @@ proc genBreakStmt(p: PProc, n: PNode) =
proc genAsmOrEmitStmt(p: PProc, n: PNode) = proc genAsmOrEmitStmt(p: PProc, n: PNode) =
genLineDir(p, n) genLineDir(p, n)
p.body.add p.indentLine(nil) p.body.add p.indentLine("")
for i in 0..<n.len: for i in 0..<n.len:
let it = n[i] let it = n[i]
case it.kind case it.kind
@ -1016,12 +1014,12 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
if it.typ.kind == tyPointer: if it.typ.kind == tyPointer:
# A fat pointer is disguised as an array # A fat pointer is disguised as an array
r.res = r.address r.res = r.address
r.address = nil r.address = ""
r.typ = etyNone r.typ = etyNone
elif r.typ == etyBaseIndex: elif r.typ == etyBaseIndex:
# Deference first # Deference first
r.res = "$1[$2]" % [r.address, r.res] r.res = "$1[$2]" % [r.address, r.res]
r.address = nil r.address = ""
r.typ = etyNone r.typ = etyNone
p.body.add(r.rdLoc) p.body.add(r.rdLoc)
@ -1055,12 +1053,12 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
line(p, repeat('}', toClose) & "\L") line(p, repeat('}', toClose) & "\L")
proc generateHeader(p: PProc, typ: PType): Rope = proc generateHeader(p: PProc, typ: PType): Rope =
result = nil result = ""
for i in 1..<typ.n.len: for i in 1..<typ.n.len:
assert(typ.n[i].kind == nkSym) assert(typ.n[i].kind == nkSym)
var param = typ.n[i].sym var param = typ.n[i].sym
if isCompileTimeOnly(param.typ): continue if isCompileTimeOnly(param.typ): continue
if result != nil: result.add(", ") if result != "": result.add(", ")
var name = mangleName(p.module, param) var name = mangleName(p.module, param)
result.add(name) result.add(name)
if mapType(param.typ) == etyBaseIndex: if mapType(param.typ) == etyBaseIndex:
@ -1135,7 +1133,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
elif b.typ == etyBaseIndex: elif b.typ == etyBaseIndex:
lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res]) lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res])
elif b.typ == etyNone: elif b.typ == etyNone:
internalAssert p.config, b.address == nil internalAssert p.config, b.address == ""
lineF(p, "$# = [$#, 0];$n", [a.address, b.res]) lineF(p, "$# = [$#, 0];$n", [a.address, b.res])
elif x.typ.kind == tyVar and y.typ.kind == tyPtr: elif x.typ.kind == tyVar and y.typ.kind == tyPtr:
lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res]) lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res])
@ -1143,13 +1141,13 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
elif a.typ == etyBaseIndex: elif a.typ == etyBaseIndex:
# array indexing may not map to var type # array indexing may not map to var type
if b.address != nil: if b.address != "":
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res]) lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
else: else:
lineF(p, "$1 = $2;$n", [a.address, b.res]) lineF(p, "$1 = $2;$n", [a.address, b.res])
else: else:
internalError(p.config, x.info, $("genAsgn", b.typ, a.typ)) internalError(p.config, x.info, $("genAsgn", b.typ, a.typ))
elif b.address != nil: elif b.address != "":
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res]) lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
else: else:
lineF(p, "$1 = $2;$n", [a.address, b.res]) lineF(p, "$1 = $2;$n", [a.address, b.res])
@ -1201,7 +1199,7 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
else: else:
if b[1].kind != nkSym: internalError(p.config, b[1].info, "genFieldAddr") if b[1].kind != nkSym: internalError(p.config, b[1].info, "genFieldAddr")
var f = b[1].sym var f = b[1].sym
if f.loc.r == nil: f.loc.r = mangleName(p.module, f) if f.loc.r == "": f.loc.r = mangleName(p.module, f)
r.res = makeJSString($f.loc.r) r.res = makeJSString($f.loc.r)
internalAssert p.config, a.typ != etyBaseIndex internalAssert p.config, a.typ != etyBaseIndex
r.address = a.res r.address = a.res
@ -1229,7 +1227,7 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
else: else:
if n[1].kind != nkSym: internalError(p.config, n[1].info, "genFieldAccess") if n[1].kind != nkSym: internalError(p.config, n[1].info, "genFieldAccess")
var f = n[1].sym var f = n[1].sym
if f.loc.r == nil: f.loc.r = mangleName(p.module, f) if f.loc.r == "": f.loc.r = mangleName(p.module, f)
r.res = "$1.$2" % [r.res, f.loc.r] r.res = "$1.$2" % [r.res, f.loc.r]
mkTemp(1) mkTemp(1)
r.kind = resExpr r.kind = resExpr
@ -1250,11 +1248,11 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
# Field symbol # Field symbol
var field = accessExpr[1].sym var field = accessExpr[1].sym
internalAssert p.config, field.kind == skField internalAssert p.config, field.kind == skField
if field.loc.r == nil: field.loc.r = mangleName(p.module, field) if field.loc.r == "": field.loc.r = mangleName(p.module, field)
# Discriminant symbol # Discriminant symbol
let disc = checkExpr[2].sym let disc = checkExpr[2].sym
internalAssert p.config, disc.kind == skField internalAssert p.config, disc.kind == skField
if disc.loc.r == nil: disc.loc.r = mangleName(p.module, disc) if disc.loc.r == "": disc.loc.r = mangleName(p.module, disc)
var setx: TCompRes var setx: TCompRes
gen(p, checkExpr[1], setx) gen(p, checkExpr[1], setx)
@ -1271,7 +1269,7 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
useMagic(p, "reprDiscriminant") # no need to offset by firstOrd unlike for cgen useMagic(p, "reprDiscriminant") # no need to offset by firstOrd unlike for cgen
let msg = genFieldDefect(p.config, field.name.s, disc) let msg = genFieldDefect(p.config, field.name.s, disc)
lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError2(makeNimstrLit($5), reprDiscriminant($2.$3, $6)); }$n", lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError2(makeNimstrLit($5), reprDiscriminant($2.$3, $6)); }$n",
setx.res, tmp, disc.loc.r, if negCheck: ~"!==" else: ~"===", setx.res, tmp, disc.loc.r, if negCheck: "!==" else: "===",
makeJSString(msg), genTypeInfo(p, disc.typ)) makeJSString(msg), genTypeInfo(p, disc.typ))
if addrTyp != nil and mapType(p, addrTyp) == etyBaseIndex: if addrTyp != nil and mapType(p, addrTyp) == etyBaseIndex:
@ -1320,7 +1318,7 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
genFieldAddr(p, n, r) genFieldAddr(p, n, r)
else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')') else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
r.typ = mapType(n.typ) r.typ = mapType(n.typ)
if r.res == nil: internalError(p.config, n.info, "genArrayAccess") if r.res == "": internalError(p.config, n.info, "genArrayAccess")
if ty.kind == tyCstring: if ty.kind == tyCstring:
r.res = "$1.charCodeAt($2)" % [r.address, r.res] r.res = "$1.charCodeAt($2)" % [r.address, r.res]
elif r.typ == etyBaseIndex: elif r.typ == etyBaseIndex:
@ -1347,11 +1345,11 @@ template isIndirect(x: PSym): bool =
proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) = proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) =
let s = n.sym let s = n.sym
if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3") if s.loc.r == "": internalError(p.config, n.info, "genAddr: 3")
case s.kind case s.kind
of skParam: of skParam:
r.res = s.loc.r r.res = s.loc.r
r.address = nil r.address = ""
r.typ = etyNone r.typ = etyNone
of skVar, skLet, skResult: of skVar, skLet, skResult:
r.kind = resExpr r.kind = resExpr
@ -1367,7 +1365,7 @@ proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) =
r.res = s.loc.r & "[0]" r.res = s.loc.r & "[0]"
else: else:
r.res = s.loc.r r.res = s.loc.r
r.address = nil r.address = ""
elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex: elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex:
# for ease of code generation, we do not distinguish between # for ease of code generation, we do not distinguish between
# sfAddrTaken and sfGlobal. # sfAddrTaken and sfGlobal.
@ -1466,7 +1464,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
var s = n.sym var s = n.sym
case s.kind case s.kind
of skVar, skLet, skParam, skTemp, skResult, skForVar: of skVar, skLet, skParam, skTemp, skResult, skForVar:
if s.loc.r == nil: if s.loc.r == "":
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s) internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
if sfCompileTime in s.flags: if sfCompileTime in s.flags:
genVarInit(p, s, if s.ast != nil: s.ast else: newNodeI(nkEmpty, s.info)) genVarInit(p, s, if s.ast != nil: s.ast else: newNodeI(nkEmpty, s.info))
@ -1491,7 +1489,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
r.res = s.loc.r r.res = s.loc.r
of skConst: of skConst:
genConstant(p, s) genConstant(p, s)
if s.loc.r == nil: if s.loc.r == "":
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s) internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
r.res = s.loc.r r.res = s.loc.r
of skProc, skFunc, skConverter, skMethod: of skProc, skFunc, skConverter, skMethod:
@ -1511,7 +1509,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
else: else:
genProcForSymIfNeeded(p, s) genProcForSymIfNeeded(p, s)
else: else:
if s.loc.r == nil: if s.loc.r == "":
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s) internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
if mapType(p, s.typ) == etyBaseIndex: if mapType(p, s.typ) == etyBaseIndex:
r.address = s.loc.r r.address = s.loc.r
@ -1536,7 +1534,7 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
r.res = "$1[1]" % [tmp] r.res = "$1[1]" % [tmp]
r.tmpLoc = tmp r.tmpLoc = tmp
elif a.typ == etyBaseIndex: elif a.typ == etyBaseIndex:
if a.tmpLoc != nil: if a.tmpLoc != "":
r.tmpLoc = a.tmpLoc r.tmpLoc = a.tmpLoc
r.res = a.rdLoc r.res = a.rdLoc
else: else:
@ -1659,9 +1657,9 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) = proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
# don't call '$' here for efficiency: # don't call '$' here for efficiency:
let f = n[0].sym let f = n[0].sym
if f.loc.r == nil: f.loc.r = mangleName(p.module, f) if f.loc.r == "": f.loc.r = mangleName(p.module, f)
if sfInfixCall in f.flags: if sfInfixCall in f.flags:
let pat = n[0].sym.loc.r.data let pat = $n[0].sym.loc.r
internalAssert p.config, pat.len > 0 internalAssert p.config, pat.len > 0
if pat.contains({'#', '(', '@'}): if pat.contains({'#', '(', '@'}):
var typ = skipTypes(n[0].typ, abstractInst) var typ = skipTypes(n[0].typ, abstractInst)
@ -1671,10 +1669,10 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
if n.len != 1: if n.len != 1:
gen(p, n[1], r) gen(p, n[1], r)
if r.typ == etyBaseIndex: if r.typ == etyBaseIndex:
if r.address == nil: if r.address == "":
globalError(p.config, n.info, "cannot invoke with infix syntax") globalError(p.config, n.info, "cannot invoke with infix syntax")
r.res = "$1[$2]" % [r.address, r.res] r.res = "$1[$2]" % [r.address, r.res]
r.address = nil r.address = ""
r.typ = etyNone r.typ = etyNone
r.res.add(".") r.res.add(".")
var op: TCompRes var op: TCompRes
@ -1826,12 +1824,12 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
result = createVar(p, lastSon t, indirect) result = createVar(p, lastSon t, indirect)
else: else:
internalError(p.config, "createVar: " & $t.kind) internalError(p.config, "createVar: " & $t.kind)
result = nil result = ""
else: else:
internalError(p.config, "createVar: " & $t.kind) internalError(p.config, "createVar: " & $t.kind)
result = nil result = ""
template returnType: untyped = ~"" template returnType: untyped = ""
proc genVarInit(p: PProc, v: PSym, n: PNode) = proc genVarInit(p: PProc, v: PSym, n: PNode) =
var var
@ -1929,8 +1927,7 @@ proc genVarStmt(p: PProc, n: PNode) =
proc genConstant(p: PProc, c: PSym) = proc genConstant(p: PProc, c: PSym) =
if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id): if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
let oldBody = p.body let oldBody = move p.body
p.body = nil
#genLineDir(p, c.ast) #genLineDir(p, c.ast)
genVarInit(p, c, c.ast) genVarInit(p, c, c.ast)
p.g.constants.add(p.body) p.g.constants.add(p.body)
@ -1984,7 +1981,7 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
else: else:
r.res.add("$1 || [])" % [a.res]) r.res.add("$1 || [])" % [a.res])
proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = nil) = proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = "") =
useMagic(p, magic) useMagic(p, magic)
r.res.add(magic & "(") r.res.add(magic & "(")
var a: TCompRes var a: TCompRes
@ -1993,7 +1990,7 @@ proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope =
if magic == "reprAny": if magic == "reprAny":
# the pointer argument in reprAny is expandend to # the pointer argument in reprAny is expandend to
# (pointedto, pointer), so we need to fill it # (pointedto, pointer), so we need to fill it
if a.address.isNil: if a.address.len == 0:
r.res.add(a.res) r.res.add(a.res)
r.res.add(", null") r.res.add(", null")
else: else:
@ -2001,14 +1998,14 @@ proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope =
else: else:
r.res.add(a.res) r.res.add(a.res)
if not typ.isNil: if typ != "":
r.res.add(", ") r.res.add(", ")
r.res.add(typ) r.res.add(typ)
r.res.add(")") r.res.add(")")
proc genRepr(p: PProc, n: PNode, r: var TCompRes) = proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
let t = skipTypes(n[1].typ, abstractVarRange) let t = skipTypes(n[1].typ, abstractVarRange)
case t.kind: case t.kind
of tyInt..tyInt64, tyUInt..tyUInt64: of tyInt..tyInt64, tyUInt..tyUInt64:
genReprAux(p, n, r, "reprInt") genReprAux(p, n, r, "reprInt")
of tyChar: of tyChar:
@ -2327,7 +2324,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
let val = it[1] let val = it[1]
gen(p, val, a) gen(p, val, a)
var f = it[0].sym var f = it[0].sym
if f.loc.r == nil: f.loc.r = mangleName(p.module, f) if f.loc.r == "": f.loc.r = mangleName(p.module, f)
fieldIDs.incl(lookupFieldAgain(nTyp, f).id) fieldIDs.incl(lookupFieldAgain(nTyp, f).id)
let typ = val.typ.skipTypes(abstractInst) let typ = val.typ.skipTypes(abstractInst)
@ -2388,7 +2385,7 @@ proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n[0][0], r) gen(p, n[0][0], r)
else: else:
gen(p, n[0], r) gen(p, n[0], r)
if r.res == nil: internalError(p.config, n.info, "convStrToCStr") if r.res == "": internalError(p.config, n.info, "convStrToCStr")
useMagic(p, "toJSStr") useMagic(p, "toJSStr")
r.res = "toJSStr($1)" % [r.res] r.res = "toJSStr($1)" % [r.res]
r.kind = resExpr r.kind = resExpr
@ -2400,7 +2397,7 @@ proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n[0][0], r) gen(p, n[0][0], r)
else: else:
gen(p, n[0], r) gen(p, n[0], r)
if r.res == nil: internalError(p.config, n.info, "convCStrToStr") if r.res == "": internalError(p.config, n.info, "convCStrToStr")
useMagic(p, "cstrToNimstr") useMagic(p, "cstrToNimstr")
r.res = "cstrToNimstr($1)" % [r.res] r.res = "cstrToNimstr($1)" % [r.res]
r.kind = resExpr r.kind = resExpr
@ -2430,11 +2427,11 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
makeJSString(prc.owner.name.s & '.' & prc.name.s), makeJSString(prc.owner.name.s & '.' & prc.name.s),
makeJSString(toFilenameOption(p.config, prc.info.fileIndex, foStacktrace))) makeJSString(toFilenameOption(p.config, prc.info.fileIndex, foStacktrace)))
else: else:
result = nil result = ""
if p.beforeRetNeeded: if p.beforeRetNeeded:
result.add p.indentLine(~"BeforeRet: {$n") result.add p.indentLine("BeforeRet: {\n")
result.add p.body result.add p.body
result.add p.indentLine(~"};$n") result.add p.indentLine("};\n")
else: else:
result.add(p.body) result.add(p.body)
if prc.typ.callConv == ccSysCall: if prc.typ.callConv == ccSysCall:
@ -2444,8 +2441,8 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
result.add(frameDestroy(p)) result.add(frameDestroy(p))
proc optionalLine(p: Rope): Rope = proc optionalLine(p: Rope): Rope =
if p == nil: if p == "":
return nil return ""
else: else:
return p & "\L" return p & "\L"
@ -2458,8 +2455,8 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
# echo "BEGIN generating code for: " & prc.name.s # echo "BEGIN generating code for: " & prc.name.s
var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options) var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
p.up = oldProc p.up = oldProc
var returnStmt: Rope = nil var returnStmt: Rope = ""
var resultAsgn: Rope = nil var resultAsgn: Rope = ""
var name = mangleName(p.module, prc) var name = mangleName(p.module, prc)
let header = generateHeader(p, prc.typ) let header = generateHeader(p, prc.typ)
if prc.typ[0] != nil and sfPure notin prc.flags: if prc.typ[0] != nil and sfPure notin prc.flags:
@ -2503,7 +2500,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
optionalLine(p.indentLine(returnStmt))]) optionalLine(p.indentLine(returnStmt))])
else: else:
# if optLineDir in p.config.options: # if optLineDir in p.config.options:
# result.add(~"\L") # result.add("\L")
if p.config.hcrOn: if p.config.hcrOn:
# Here, we introduce thunks that create the equivalent of a jump table # Here, we introduce thunks that create the equivalent of a jump table
@ -2526,7 +2523,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
dec p.extraIndent dec p.extraIndent
result.add p.indentLine(def) result.add p.indentLine(def)
result.add p.indentLine(~"}$n") result.add p.indentLine("}\n")
#if gVerbosity >= 3: #if gVerbosity >= 3:
# echo "END generated code for: " & prc.name.s # echo "END generated code for: " & prc.name.s
@ -2534,7 +2531,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
proc genStmt(p: PProc, n: PNode) = proc genStmt(p: PProc, n: PNode) =
var r: TCompRes var r: TCompRes
gen(p, n, r) gen(p, n, r)
if r.res != nil: lineF(p, "$#;$n", [r.res]) if r.res != "": lineF(p, "$#;$n", [r.res])
proc genPragma(p: PProc, n: PNode) = proc genPragma(p: PProc, n: PNode) =
for it in n.sons: for it in n.sons:
@ -2574,7 +2571,7 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) =
r.res = "($1 - ($2 $3))" % [rope minuend, r.res, trimmer] r.res = "($1 - ($2 $3))" % [rope minuend, r.res, trimmer]
elif (src.kind == tyPtr and mapType(p, src) == etyObject) and dest.kind == tyPointer: elif (src.kind == tyPtr and mapType(p, src) == etyObject) and dest.kind == tyPointer:
r.address = r.res r.address = r.res
r.res = ~"null" r.res = "null"
r.typ = etyBaseIndex r.typ = etyBaseIndex
elif (dest.kind == tyPtr and mapType(p, dest) == etyObject) and src.kind == tyPointer: elif (dest.kind == tyPtr and mapType(p, dest) == etyObject) and src.kind == tyPointer:
r.res = r.address r.res = r.address
@ -2583,8 +2580,8 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) =
proc gen(p: PProc, n: PNode, r: var TCompRes) = proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.typ = etyNone r.typ = etyNone
if r.kind != resCallee: r.kind = resNone if r.kind != resCallee: r.kind = resNone
#r.address = nil #r.address = ""
r.res = nil r.res = ""
case n.kind case n.kind
of nkSym: of nkSym:
@ -2723,7 +2720,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
var s = n[namePos].sym var s = n[namePos].sym
if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}: if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
genSym(p, n[namePos], r) genSym(p, n[namePos], r)
r.res = nil r.res = ""
of nkGotoState, nkState: of nkGotoState, nkState:
globalError(p.config, n.info, "First class iterators not implemented") globalError(p.config, n.info, "First class iterators not implemented")
of nkPragmaBlock: gen(p, n.lastSon, r) of nkPragmaBlock: gen(p, n.lastSon, r)
@ -2840,7 +2837,7 @@ proc getClassName(t: PType): Rope =
s = skipTypes(t, abstractPtrs).sym s = skipTypes(t, abstractPtrs).sym
if s.isNil or sfAnon in s.flags: if s.isNil or sfAnon in s.flags:
doAssert(false, "cannot retrieve class name") doAssert(false, "cannot retrieve class name")
if s.loc.r != nil: result = s.loc.r if s.loc.r != "": result = s.loc.r
else: result = rope(s.name.s) else: result = rope(s.name.s)
proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =

View file

@ -19,13 +19,13 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
s, u: Rope s, u: Rope
field: PSym field: PSym
b: PNode b: PNode
result = nil result = ""
case n.kind case n.kind
of nkRecList: of nkRecList:
if n.len == 1: if n.len == 1:
result = genObjectFields(p, typ, n[0]) result = genObjectFields(p, typ, n[0])
else: else:
s = nil s = ""
for i in 0..<n.len: for i in 0..<n.len:
if i > 0: s.add(", \L") if i > 0: s.add(", \L")
s.add(genObjectFields(p, typ, n[i])) s.add(genObjectFields(p, typ, n[i]))
@ -44,13 +44,13 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
s = genTypeInfo(p, field.typ) s = genTypeInfo(p, field.typ)
for i in 1..<n.len: for i in 1..<n.len:
b = n[i] # branch b = n[i] # branch
u = nil u = ""
case b.kind case b.kind
of nkOfBranch: of nkOfBranch:
if b.len < 2: if b.len < 2:
internalError(p.config, b.info, "genObjectFields; nkOfBranch broken") internalError(p.config, b.info, "genObjectFields; nkOfBranch broken")
for j in 0..<b.len - 1: for j in 0..<b.len - 1:
if u != nil: u.add(", ") if u != "": u.add(", ")
if b[j].kind == nkRange: if b[j].kind == nkRange:
u.addf("[$1, $2]", [rope(getOrdValue(b[j][0])), u.addf("[$1, $2]", [rope(getOrdValue(b[j][0])),
rope(getOrdValue(b[j][1]))]) rope(getOrdValue(b[j][1]))])
@ -59,7 +59,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
of nkElse: of nkElse:
u = rope(lengthOrd(p.config, field.typ)) u = rope(lengthOrd(p.config, field.typ))
else: internalError(p.config, n.info, "genObjectFields(nkRecCase)") else: internalError(p.config, n.info, "genObjectFields(nkRecCase)")
if result != nil: result.add(", \L") if result != "": result.add(", \L")
result.addf("[setConstr($1), $2]", result.addf("[setConstr($1), $2]",
[u, genObjectFields(p, typ, lastSon(b))]) [u, genObjectFields(p, typ, lastSon(b))])
result = ("{kind: 3, offset: \"$1\", len: $3, " & result = ("{kind: 3, offset: \"$1\", len: $3, " &
@ -84,7 +84,7 @@ proc genObjectInfo(p: PProc, typ: PType, name: Rope) =
[name, genTypeInfo(p, typ[0].skipTypes(skipPtrs))]) [name, genTypeInfo(p, typ[0].skipTypes(skipPtrs))])
proc genTupleFields(p: PProc, typ: PType): Rope = proc genTupleFields(p: PProc, typ: PType): Rope =
var s: Rope = nil var s: Rope = ""
for i in 0..<typ.len: for i in 0..<typ.len:
if i > 0: s.add(", \L") if i > 0: s.add(", \L")
s.addf("{kind: 1, offset: \"Field$1\", len: 0, " & s.addf("{kind: 1, offset: \"Field$1\", len: 0, " &
@ -102,7 +102,7 @@ proc genTupleInfo(p: PProc, typ: PType, name: Rope) =
p.g.typeInfo.addf("$1.node = NNI$2;$n", [name, rope(typ.id)]) p.g.typeInfo.addf("$1.node = NNI$2;$n", [name, rope(typ.id)])
proc genEnumInfo(p: PProc, typ: PType, name: Rope) = proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
var s: Rope = nil var s: Rope = ""
for i in 0..<typ.n.len: for i in 0..<typ.n.len:
if (typ.n[i].kind != nkSym): internalError(p.config, typ.n.info, "genEnumInfo") if (typ.n[i].kind != nkSym): internalError(p.config, typ.n.info, "genEnumInfo")
let field = typ.n[i].sym let field = typ.n[i].sym

View file

@ -10,7 +10,9 @@
import import
std/[strutils, os, tables, terminal, macros, times], std/[strutils, os, tables, terminal, macros, times],
std/private/miscdollars, std/private/miscdollars,
options, ropes, lineinfos, pathutils, strutils2 options, lineinfos, pathutils, strutils2
import ropes except `%`
when defined(nimPreviewSlimSystem): when defined(nimPreviewSlimSystem):
import std/[syncio, assertions] import std/[syncio, assertions]
@ -43,18 +45,16 @@ proc toCChar*(c: char; result: var string) {.inline.} =
result.add c result.add c
proc makeCString*(s: string): Rope = proc makeCString*(s: string): Rope =
result = nil result = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1) result.add("\"")
res.add("\"")
for i in 0..<s.len: for i in 0..<s.len:
# line wrapping of string litterals in cgen'd code was a bad idea, e.g. causes: bug #16265 # line wrapping of string litterals in cgen'd code was a bad idea, e.g. causes: bug #16265
# It also makes reading c sources or grepping harder, for zero benefit. # It also makes reading c sources or grepping harder, for zero benefit.
# const MaxLineLength = 64 # const MaxLineLength = 64
# if (i + 1) mod MaxLineLength == 0: # if (i + 1) mod MaxLineLength == 0:
# res.add("\"\L\"") # res.add("\"\L\"")
toCChar(s[i], res) toCChar(s[i], result)
res.add('\"') result.add('\"')
result.add(rope(res))
proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo = proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo =
result.fullPath = fullPath result.fullPath = fullPath

View file

@ -960,7 +960,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
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 = rope(sym.name.s) if sym.loc.r == "": sym.loc.r = rope(sym.name.s)
of wNoSideEffect: of wNoSideEffect:
noVal(c, it) noVal(c, it)
if sym != nil: if sym != nil:
@ -1290,7 +1290,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
sfImportc in sym.flags and lib != nil: sfImportc in sym.flags and lib != nil:
incl(sym.loc.flags, lfDynamicLib) incl(sym.loc.flags, lfDynamicLib)
addToLib(lib, sym) addToLib(lib, sym)
if sym.loc.r == nil: sym.loc.r = rope(sym.name.s) if sym.loc.r == "": sym.loc.r = rope(sym.name.s)
proc hasPragma*(n: PNode, pragma: TSpecialWord): bool = proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
if n == nil: return false if n == nil: return false

View file

@ -7,217 +7,57 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# Ropes for the C code generator # Ropes for the C code generator. Ropes are mapped to `string` directly nowadays.
#
# Ropes are a data structure that represents a very long string
# efficiently; especially concatenation is done in O(1) instead of O(N).
# Ropes make use a lazy evaluation: They are essentially concatenation
# trees that are only flattened when converting to a native Nim
# string or when written to disk. The empty string is represented by a
# nil pointer.
# A little picture makes everything clear:
#
# "this string" & " is internally " & "represented as"
#
# con -- inner nodes do not contain raw data
# / \
# / \
# / \
# con "represented as"
# / \
# / \
# / \
# / \
# / \
#"this string" " is internally "
#
# Note that this is the same as:
# "this string" & (" is internally " & "represented as")
#
# con
# / \
# / \
# / \
# "this string" con
# / \
# / \
# / \
# / \
# / \
#" is internally " "represented as"
#
# The 'con' operator is associative! This does not matter however for
# the algorithms we use for ropes.
#
# Note that the left and right pointers are not needed for leaves.
# Leaves have relatively high memory overhead (~30 bytes on a 32
# bit machines) and we produce many of them. This is why we cache and
# share leaves across different rope trees.
# To cache them they are inserted in a `cache` array.
import import hashes
hashes
from pathutils import AbsoluteFile from pathutils import AbsoluteFile
when defined(nimPreviewSlimSystem): when defined(nimPreviewSlimSystem):
import std/[assertions, syncio, formatfloat] import std/[assertions, syncio, formatfloat]
type type
FormatStr* = string # later we may change it to CString for better FormatStr* = string # later we may change it to CString for better
# performance of the code generator (assignments # performance of the code generator (assignments
# copy the format strings # copy the format strings
# though it is not necessary) # though it is not necessary)
Rope* = ref RopeObj Rope* = string
RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented
# by nil to safe space
left, right: Rope
L: int # <= 0 if a leaf
data*: string
proc len*(a: Rope): int = proc newRopeAppender*(): string {.inline.} =
## the rope's length result = newString(0)
if a == nil: result = 0
else: result = abs a.L
proc newRope(data: string = ""): Rope = proc freeze*(r: Rope) {.inline.} = discard
new(result)
result.L = -data.len
result.data = data
when compileOption("tlsEmulation"): # fixme: be careful if you want to make ropes support multiple threads proc resetRopeCache* = discard
var
cache: array[0..2048*2 - 1, Rope]
else:
var
cache {.threadvar.} : array[0..2048*2 - 1, Rope]
proc resetRopeCache* = template rope*(s: string): string = s
for i in low(cache)..high(cache):
cache[i] = nil
proc ropeInvariant(r: Rope): bool =
if r == nil:
result = true
else:
result = true #
# if r.data <> snil then
# result := true
# else begin
# result := (r.left <> nil) and (r.right <> nil);
# if result then result := ropeInvariant(r.left);
# if result then result := ropeInvariant(r.right);
# end
var gCacheTries* = 0
var gCacheMisses* = 0
var gCacheIntTries* = 0
proc insertInCache(s: string): Rope =
inc gCacheTries
var h = hash(s) and high(cache)
result = cache[h]
if isNil(result) or result.data != s:
inc gCacheMisses
result = newRope(s)
cache[h] = result
proc rope*(s: string): Rope =
## Converts a string to a rope.
if s.len == 0:
result = nil
else:
result = insertInCache(s)
assert(ropeInvariant(result))
proc rope*(i: BiggestInt): Rope = proc rope*(i: BiggestInt): Rope =
## Converts an int to a rope. ## Converts an int to a rope.
inc gCacheIntTries
result = rope($i) result = rope($i)
proc rope*(f: BiggestFloat): Rope = proc rope*(f: BiggestFloat): Rope =
## Converts a float to a rope. ## Converts a float to a rope.
result = rope($f) result = rope($f)
proc `&`*(a, b: Rope): Rope =
if a == nil:
result = b
elif b == nil:
result = a
else:
result = newRope()
result.L = abs(a.L) + abs(b.L)
result.left = a
result.right = b
proc `&`*(a: Rope, b: string): Rope =
## the concatenation operator for ropes.
result = a & rope(b)
proc `&`*(a: string, b: Rope): Rope =
## the concatenation operator for ropes.
result = rope(a) & b
proc `&`*(a: openArray[Rope]): Rope =
## the concatenation operator for an openarray of ropes.
for i in 0..high(a): result = result & a[i]
proc add*(a: var Rope, b: Rope) =
## adds `b` to the rope `a`.
a = a & b
proc add*(a: var Rope, b: string) =
## adds `b` to the rope `a`.
a = a & b
iterator leaves*(r: Rope): string =
## iterates over any leaf string in the rope `r`.
if r != nil:
var stack = @[r]
while stack.len > 0:
var it = stack.pop
while it.left != nil:
assert it.right != nil
stack.add(it.right)
it = it.left
assert(it != nil)
yield it.data
iterator items*(r: Rope): char =
## iterates over any character in the rope `r`.
for s in leaves(r):
for c in items(s): yield c
proc writeRope*(f: File, r: Rope) = proc writeRope*(f: File, r: Rope) =
## writes a rope to a file. ## writes a rope to a file.
for s in leaves(r): write(f, s) write(f, r)
proc writeRope*(head: Rope, filename: AbsoluteFile): bool = proc writeRope*(head: Rope, filename: AbsoluteFile): bool =
var f: File var f: File
if open(f, filename.string, fmWrite): if open(f, filename.string, fmWrite):
if head != nil: writeRope(f, head) writeRope(f, head)
close(f) close(f)
result = true result = true
else: else:
result = false result = false
proc `$`*(r: Rope): string =
## converts a rope back to a string.
result = newString(r.len)
setLen(result, 0)
for s in leaves(r): result.add(s)
proc ropeConcat*(a: varargs[Rope]): Rope =
# not overloaded version of concat to speed-up `rfmt` a little bit
for i in 0..high(a): result = result & a[i]
proc prepend*(a: var Rope, b: Rope) = a = b & a
proc prepend*(a: var Rope, b: string) = a = b & a proc prepend*(a: var Rope, b: string) = a = b & a
proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope = proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
var i = 0 var i = 0
result = nil result = newRopeAppender()
var num = 0 var num = 0
while i < frmt.len: while i < frmt.len:
if frmt[i] == '$': if frmt[i] == '$':
@ -270,7 +110,6 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
else: break else: break
if i - 1 >= start: if i - 1 >= start:
result.add(substr(frmt, start, i - 1)) result.add(substr(frmt, start, i - 1))
assert(ropeInvariant(result))
proc `%`*(frmt: static[FormatStr], args: openArray[Rope]): Rope = proc `%`*(frmt: static[FormatStr], args: openArray[Rope]): Rope =
runtimeFormat(frmt, args) runtimeFormat(frmt, args)
@ -279,21 +118,10 @@ template addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
## shortcut for ``add(c, frmt % args)``. ## shortcut for ``add(c, frmt % args)``.
c.add(frmt % args) c.add(frmt % args)
when true:
template `~`*(r: string): Rope = r % []
else:
{.push stack_trace: off, line_trace: off.}
proc `~`*(r: static[string]): Rope =
# this is the new optimized "to rope" operator
# the mnemonic is that `~` looks a bit like a rope :)
var r {.global.} = r % []
return r
{.pop.}
const const
bufSize = 1024 # 1 KB is reasonable bufSize = 1024 # 1 KB is reasonable
proc equalsFile*(r: Rope, f: File): bool = proc equalsFile*(s: Rope, f: File): bool =
## returns true if the contents of the file `f` equal `r`. ## returns true if the contents of the file `f` equal `r`.
var var
buf: array[bufSize, char] buf: array[bufSize, char]
@ -302,7 +130,7 @@ proc equalsFile*(r: Rope, f: File): bool =
btotal = 0 btotal = 0
rtotal = 0 rtotal = 0
for s in leaves(r): when true:
var spos = 0 var spos = 0
rtotal += s.len rtotal += s.len
while spos < s.len: while spos < s.len:

View file

@ -2259,7 +2259,7 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
# codegen would fail: # codegen would fail:
if sfCompilerProc in result.flags: if sfCompilerProc in result.flags:
result.flags.excl {sfCompilerProc, sfExportc, sfImportc} result.flags.excl {sfCompilerProc, sfExportc, sfImportc}
result.loc.r = nil result.loc.r = ""
proc setMs(n: PNode, s: PSym): PNode = proc setMs(n: PNode, s: PSym): PNode =
result = n result = n
@ -2836,7 +2836,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
defer: defer:
if isCompilerDebug(): if isCompilerDebug():
echo ("<", c.config$n.info, n, ?.result.typ) echo ("<", c.config$n.info, n, ?.result.typ)
template directLiteral(typeKind: TTypeKind) = template directLiteral(typeKind: TTypeKind) =
if result.typ == nil: if result.typ == nil:
if expectedType != nil and ( if expectedType != nil and (

View file

@ -824,7 +824,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
f.options = c.config.options f.options = c.config.options
if fieldOwner != nil and if fieldOwner != nil and
{sfImportc, sfExportc} * fieldOwner.flags != {} and {sfImportc, sfExportc} * fieldOwner.flags != {} and
not hasCaseFields and f.loc.r == nil: not hasCaseFields and f.loc.r == "":
f.loc.r = rope(f.name.s) f.loc.r = rope(f.name.s)
f.flags.incl {sfImportc, sfExportc} * fieldOwner.flags f.flags.incl {sfImportc, sfExportc} * fieldOwner.flags
inc(pos) inc(pos)

View file

@ -21,8 +21,7 @@ proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
proc `&=`(c: var MD5Context, ch: char) = proc `&=`(c: var MD5Context, ch: char) =
# XXX suspicious code here; relies on ch being zero terminated? # XXX suspicious code here; relies on ch being zero terminated?
md5Update(c, unsafeAddr ch, 1) md5Update(c, unsafeAddr ch, 1)
proc `&=`(c: var MD5Context, r: Rope) =
for l in leaves(r): md5Update(c, l.cstring, l.len)
proc `&=`(c: var MD5Context, i: BiggestInt) = proc `&=`(c: var MD5Context, i: BiggestInt) =
md5Update(c, cast[cstring](unsafeAddr i), sizeof(i)) md5Update(c, cast[cstring](unsafeAddr i), sizeof(i))
proc `&=`(c: var MD5Context, f: BiggestFloat) = proc `&=`(c: var MD5Context, f: BiggestFloat) =
@ -150,7 +149,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
# is actually safe without an infinite recursion check: # is actually safe without an infinite recursion check:
if t.sym != nil: if t.sym != nil:
if {sfCompilerProc} * t.sym.flags != {}: if {sfCompilerProc} * t.sym.flags != {}:
doAssert t.sym.loc.r != nil doAssert t.sym.loc.r != ""
# The user has set a specific name for this type # The user has set a specific name for this type
c &= t.sym.loc.r c &= t.sym.loc.r
elif CoOwnerSig in flags: elif CoOwnerSig in flags: