mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-06 20:04:18 +00:00
Merge branch 'devel' into expand-amb-identifier-output
This commit is contained in:
@@ -644,7 +644,7 @@ type
|
||||
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
|
||||
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
||||
mMove, mWasMoved, mDestroy,
|
||||
mDefault, mAccessEnv, mReset,
|
||||
mDefault, mUnown, mAccessEnv, mReset,
|
||||
mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs,
|
||||
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
|
||||
mOrdinal,
|
||||
@@ -877,6 +877,13 @@ type
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
TLockLevel* = distinct int16
|
||||
|
||||
TTypeAttachedOp* = enum ## as usual, order is important here
|
||||
attachedDestructor,
|
||||
attachedAsgn,
|
||||
attachedSink,
|
||||
attachedDeepCopy
|
||||
|
||||
TType* {.acyclic.} = object of TIdObj # \
|
||||
# types are identical iff they have the
|
||||
# same id; there may be multiple copies of a type
|
||||
@@ -897,12 +904,7 @@ type
|
||||
owner*: PSym # the 'owner' of the type
|
||||
sym*: PSym # types have the sym associated with them
|
||||
# it is used for converting types to strings
|
||||
destructor*: PSym # destructor. warning: nil here may not necessary
|
||||
# mean that there is no destructor.
|
||||
# see instantiateDestructor in semdestruct.nim
|
||||
deepCopy*: PSym # overriden 'deepCopy' operation
|
||||
assignment*: PSym # overriden '=' operation
|
||||
sink*: PSym # overriden '=sink' operation
|
||||
attachedOps*: array[TTypeAttachedOp, PSym] # destructors, etc.
|
||||
methods*: seq[(int,PSym)] # attached methods
|
||||
size*: BiggestInt # the size of the type in bytes
|
||||
# -1 means that the size is unkwown
|
||||
@@ -1275,6 +1277,7 @@ const
|
||||
UnspecifiedLockLevel* = TLockLevel(-1'i16)
|
||||
MaxLockLevel* = 1000'i16
|
||||
UnknownLockLevel* = TLockLevel(1001'i16)
|
||||
AttachedOpToStr*: array[TTypeAttachedOp, string] = ["=destroy", "=", "=sink", "=deepcopy"]
|
||||
|
||||
proc `$`*(x: TLockLevel): string =
|
||||
if x.ord == UnspecifiedLockLevel.ord: result = "<unspecified>"
|
||||
@@ -1341,10 +1344,7 @@ proc assignType*(dest, src: PType) =
|
||||
dest.n = src.n
|
||||
dest.size = src.size
|
||||
dest.align = src.align
|
||||
dest.destructor = src.destructor
|
||||
dest.deepCopy = src.deepCopy
|
||||
dest.sink = src.sink
|
||||
dest.assignment = src.assignment
|
||||
dest.attachedOps = src.attachedOps
|
||||
dest.lockLevel = src.lockLevel
|
||||
# this fixes 'type TLock = TSysLock':
|
||||
if src.sym != nil:
|
||||
@@ -1831,3 +1831,7 @@ proc addParam*(procType: PType; param: PSym) =
|
||||
param.position = procType.len-1
|
||||
addSon(procType.n, newSymNode(param))
|
||||
rawAddSon(procType, param.typ)
|
||||
|
||||
template destructor*(t: PType): PSym = t.attachedOps[attachedDestructor]
|
||||
template assignment*(t: PType): PSym = t.attachedOps[attachedAsgn]
|
||||
template asink*(t: PType): PSym = t.attachedOps[attachedSink]
|
||||
|
||||
@@ -46,13 +46,23 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
else:
|
||||
add(pl, ~")")
|
||||
if p.module.compileToCpp and lfSingleUse in d.flags:
|
||||
# do not generate spurious temporaries for C++! For C we're better off
|
||||
# with them to prevent undefined behaviour and because the codegen
|
||||
# is free to emit expressions multiple times!
|
||||
d.k = locCall
|
||||
d.r = pl
|
||||
excl d.flags, lfSingleUse
|
||||
if p.module.compileToCpp:
|
||||
if lfSingleUse in d.flags:
|
||||
# do not generate spurious temporaries for C++! For C we're better off
|
||||
# with them to prevent undefined behaviour and because the codegen
|
||||
# is free to emit expressions multiple times!
|
||||
d.k = locCall
|
||||
d.r = pl
|
||||
excl d.flags, lfSingleUse
|
||||
else:
|
||||
if d.k == locNone and p.splitDecls == 0:
|
||||
getTempCpp(p, typ.sons[0], d, pl)
|
||||
else:
|
||||
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
@@ -218,10 +228,12 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
genParamLoop(pl)
|
||||
|
||||
template genCallPattern {.dirty.} =
|
||||
lineF(p, cpsStmts, callPattern & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
|
||||
if tfIterator in typ.flags:
|
||||
lineF(p, cpsStmts, PatIter & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
|
||||
else:
|
||||
lineF(p, cpsStmts, PatProc & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
|
||||
|
||||
let rawProc = getRawProcType(p, typ)
|
||||
let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
|
||||
if typ.sons[0] != nil:
|
||||
if isInvalidReturnType(p.config, typ.sons[0]):
|
||||
if sonsLen(ri) > 1: add(pl, ~", ")
|
||||
@@ -246,7 +258,11 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
list.r = callPattern % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
if tfIterator in typ.flags:
|
||||
list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
else:
|
||||
list.r = PatProc % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
genCallPattern()
|
||||
|
||||
@@ -99,17 +99,17 @@ proc bitSetToWord(s: TBitSet, size: int): BiggestInt =
|
||||
if j < len(s): result = result or (ze64(s[j]) shl (j * 8))
|
||||
|
||||
proc genRawSetData(cs: TBitSet, size: int): Rope =
|
||||
var frmt: FormatStr
|
||||
if size > 8:
|
||||
result = "{$n" % []
|
||||
for i in countup(0, size - 1):
|
||||
if i < size - 1:
|
||||
# not last iteration?
|
||||
if (i + 1) mod 8 == 0: frmt = "0x$1,$n"
|
||||
else: frmt = "0x$1, "
|
||||
if (i + 1) mod 8 == 0:
|
||||
addf(result, "0x$1,$n", [rope(toHex(ze64(cs[i]), 2))])
|
||||
else:
|
||||
addf(result, "0x$1, ", [rope(toHex(ze64(cs[i]), 2))])
|
||||
else:
|
||||
frmt = "0x$1}$n"
|
||||
addf(result, frmt, [rope(toHex(ze64(cs[i]), 2))])
|
||||
addf(result, "0x$1}$n", [rope(toHex(ze64(cs[i]), 2))])
|
||||
else:
|
||||
result = intLiteral(bitSetToWord(cs, size))
|
||||
# result := rope('0x' + ToHex(bitSetToWord(cs, size), size * 2))
|
||||
@@ -510,10 +510,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
"mulInt64", "divInt64", "modInt64",
|
||||
"addInt64", "subInt64"
|
||||
]
|
||||
opr: array[mAddI..mPred, string] = [
|
||||
"($#)($# + $#)", "($#)($# - $#)", "($#)($# * $#)",
|
||||
"($#)($# / $#)", "($#)($# % $#)",
|
||||
"($#)($# + $#)", "($#)($# - $#)"]
|
||||
opr: array[mAddI..mPred, string] = ["+", "-", "*", "/", "%", "+", "-"]
|
||||
var a, b: TLoc
|
||||
assert(e.sons[1].typ != nil)
|
||||
assert(e.sons[2].typ != nil)
|
||||
@@ -523,7 +520,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
# later via 'chckRange'
|
||||
let t = e.typ.skipTypes(abstractRange)
|
||||
if optOverflowCheck notin p.options:
|
||||
let res = opr[m] % [getTypeDesc(p.module, e.typ), rdLoc(a), rdLoc(b)]
|
||||
let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
|
||||
putIntoDest(p, d, e, res)
|
||||
else:
|
||||
let res = binaryArithOverflowRaw(p, t, a, b,
|
||||
@@ -531,11 +528,6 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res])
|
||||
|
||||
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
const
|
||||
opr: array[mUnaryMinusI..mAbsI, string] = [
|
||||
mUnaryMinusI: "((NI$2)-($1))",
|
||||
mUnaryMinusI64: "-($1)",
|
||||
mAbsI: "($1 > 0? ($1) : -($1))"]
|
||||
var
|
||||
a: TLoc
|
||||
t: PType
|
||||
@@ -545,54 +537,17 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
if optOverflowCheck in p.options:
|
||||
linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n",
|
||||
[rdLoc(a), intLiteral(firstOrd(p.config, t))])
|
||||
putIntoDest(p, d, e, opr[m] % [rdLoc(a), rope(getSize(p.config, t) * 8)])
|
||||
case m
|
||||
of mUnaryMinusI:
|
||||
putIntoDest(p, d, e, "((NI$2)-($1))" % [rdLoc(a), rope(getSize(p.config, t) * 8)])
|
||||
of mUnaryMinusI64:
|
||||
putIntoDest(p, d, e, "-($1)" % [rdLoc(a)])
|
||||
of mAbsI:
|
||||
putIntoDest(p, d, e, "($1 > 0? ($1) : -($1))" % [rdLoc(a)])
|
||||
else:
|
||||
assert(false, $m)
|
||||
|
||||
proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
const
|
||||
binArithTab: array[mAddF64..mXor, string] = [
|
||||
"(($4)($1) + ($4)($2))", # AddF64
|
||||
"(($4)($1) - ($4)($2))", # SubF64
|
||||
"(($4)($1) * ($4)($2))", # MulF64
|
||||
"(($4)($1) / ($4)($2))", # DivF64
|
||||
"($4)((NU$5)($1) >> (NU$3)($2))", # ShrI
|
||||
"($4)((NU$3)($1) << (NU$3)($2))", # ShlI
|
||||
"($4)((NI$3)($1) >> (NU$3)($2))", # AshrI
|
||||
"($4)($1 & $2)", # BitandI
|
||||
"($4)($1 | $2)", # BitorI
|
||||
"($4)($1 ^ $2)", # BitxorI
|
||||
"(($1 <= $2) ? $1 : $2)", # MinI
|
||||
"(($1 >= $2) ? $1 : $2)", # MaxI
|
||||
"(($1 <= $2) ? $1 : $2)", # MinF64
|
||||
"(($1 >= $2) ? $1 : $2)", # MaxF64
|
||||
"($4)((NU$3)($1) + (NU$3)($2))", # AddU
|
||||
"($4)((NU$3)($1) - (NU$3)($2))", # SubU
|
||||
"($4)((NU$3)($1) * (NU$3)($2))", # MulU
|
||||
"($4)((NU$3)($1) / (NU$3)($2))", # DivU
|
||||
"($4)((NU$3)($1) % (NU$3)($2))", # ModU
|
||||
"($1 == $2)", # EqI
|
||||
"($1 <= $2)", # LeI
|
||||
"($1 < $2)", # LtI
|
||||
"($1 == $2)", # EqF64
|
||||
"($1 <= $2)", # LeF64
|
||||
"($1 < $2)", # LtF64
|
||||
"((NU$3)($1) <= (NU$3)($2))", # LeU
|
||||
"((NU$3)($1) < (NU$3)($2))", # LtU
|
||||
"((NU64)($1) <= (NU64)($2))", # LeU64
|
||||
"((NU64)($1) < (NU64)($2))", # LtU64
|
||||
"($1 == $2)", # EqEnum
|
||||
"($1 <= $2)", # LeEnum
|
||||
"($1 < $2)", # LtEnum
|
||||
"((NU8)($1) == (NU8)($2))", # EqCh
|
||||
"((NU8)($1) <= (NU8)($2))", # LeCh
|
||||
"((NU8)($1) < (NU8)($2))", # LtCh
|
||||
"($1 == $2)", # EqB
|
||||
"($1 <= $2)", # LeB
|
||||
"($1 < $2)", # LtB
|
||||
"($1 == $2)", # EqRef
|
||||
"($1 == $2)", # EqPtr
|
||||
"($1 <= $2)", # LePtr
|
||||
"($1 < $2)", # LtPtr
|
||||
"($1 != $2)"] # Xor
|
||||
var
|
||||
a, b: TLoc
|
||||
s, k: BiggestInt
|
||||
@@ -603,9 +558,59 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
# BUGFIX: cannot use result-type here, as it may be a boolean
|
||||
s = max(getSize(p.config, a.t), getSize(p.config, b.t)) * 8
|
||||
k = getSize(p.config, a.t) * 8
|
||||
putIntoDest(p, d, e,
|
||||
binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s),
|
||||
getSimpleTypeDesc(p.module, e.typ), rope(k)])
|
||||
|
||||
template applyFormat(frmt: untyped) =
|
||||
putIntoDest(p, d, e, frmt % [
|
||||
rdLoc(a), rdLoc(b), rope(s),
|
||||
getSimpleTypeDesc(p.module, e.typ), rope(k)]
|
||||
)
|
||||
|
||||
case op
|
||||
of mAddF64: applyFormat("(($4)($1) + ($4)($2))")
|
||||
of mSubF64: applyFormat("(($4)($1) - ($4)($2))")
|
||||
of mMulF64: applyFormat("(($4)($1) * ($4)($2))")
|
||||
of mDivF64: applyFormat("(($4)($1) / ($4)($2))")
|
||||
of mShrI: applyFormat("($4)((NU$5)($1) >> (NU$3)($2))")
|
||||
of mShlI: applyFormat("($4)((NU$3)($1) << (NU$3)($2))")
|
||||
of mAshrI: applyFormat("($4)((NI$3)($1) >> (NU$3)($2))")
|
||||
of mBitandI: applyFormat("($4)($1 & $2)")
|
||||
of mBitorI: applyFormat("($4)($1 | $2)")
|
||||
of mBitxorI: applyFormat("($4)($1 ^ $2)")
|
||||
of mMinI: applyFormat("(($1 <= $2) ? $1 : $2)")
|
||||
of mMaxI: applyFormat("(($1 >= $2) ? $1 : $2)")
|
||||
of mMinF64: applyFormat("(($1 <= $2) ? $1 : $2)")
|
||||
of mMaxF64: applyFormat("(($1 >= $2) ? $1 : $2)")
|
||||
of mAddU: applyFormat("($4)((NU$3)($1) + (NU$3)($2))")
|
||||
of mSubU: applyFormat("($4)((NU$3)($1) - (NU$3)($2))")
|
||||
of mMulU: applyFormat("($4)((NU$3)($1) * (NU$3)($2))")
|
||||
of mDivU: applyFormat("($4)((NU$3)($1) / (NU$3)($2))")
|
||||
of mModU: applyFormat("($4)((NU$3)($1) % (NU$3)($2))")
|
||||
of mEqI: applyFormat("($1 == $2)")
|
||||
of mLeI: applyFormat("($1 <= $2)")
|
||||
of mLtI: applyFormat("($1 < $2)")
|
||||
of mEqF64: applyFormat("($1 == $2)")
|
||||
of mLeF64: applyFormat("($1 <= $2)")
|
||||
of mLtF64: applyFormat("($1 < $2)")
|
||||
of mLeU: applyFormat("((NU$3)($1) <= (NU$3)($2))")
|
||||
of mLtU: applyFormat("((NU$3)($1) < (NU$3)($2))")
|
||||
of mLeU64: applyFormat("((NU64)($1) <= (NU64)($2))")
|
||||
of mLtU64: applyFormat("((NU64)($1) < (NU64)($2))")
|
||||
of mEqEnum: applyFormat("($1 == $2)")
|
||||
of mLeEnum: applyFormat("($1 <= $2)")
|
||||
of mLtEnum: applyFormat("($1 < $2)")
|
||||
of mEqCh: applyFormat("((NU8)($1) == (NU8)($2))")
|
||||
of mLeCh: applyFormat("((NU8)($1) <= (NU8)($2))")
|
||||
of mLtCh: applyFormat("((NU8)($1) < (NU8)($2))")
|
||||
of mEqB: applyFormat("($1 == $2)")
|
||||
of mLeB: applyFormat("($1 <= $2)")
|
||||
of mLtB: applyFormat("($1 < $2)")
|
||||
of mEqRef: applyFormat("($1 == $2)")
|
||||
of mEqUntracedRef: applyFormat("($1 == $2)")
|
||||
of mLePtr: applyFormat("($1 <= $2)")
|
||||
of mLtPtr: applyFormat("($1 < $2)")
|
||||
of mXor: applyFormat("($1 != $2)")
|
||||
else:
|
||||
assert(false, $op)
|
||||
|
||||
proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
|
||||
var a, b: TLoc
|
||||
@@ -628,7 +633,8 @@ proc genIsNil(p: BProc, e: PNode, d: var TLoc) =
|
||||
|
||||
proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
const
|
||||
unArithTab: array[mNot..mToBiggestInt, string] = ["!($1)", # Not
|
||||
unArithTab: array[mNot..mToBiggestInt, string] = [
|
||||
"!($1)", # Not
|
||||
"$1", # UnaryPlusI
|
||||
"($3)((NU$2) ~($1))", # BitnotI
|
||||
"$1", # UnaryPlusF64
|
||||
@@ -654,10 +660,58 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
assert(e.sons[1].typ != nil)
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
t = skipTypes(e.typ, abstractRange)
|
||||
putIntoDest(p, d, e,
|
||||
unArithTab[op] % [rdLoc(a), rope(getSize(p.config, t) * 8),
|
||||
|
||||
|
||||
template applyFormat(frmt: untyped) =
|
||||
putIntoDest(p, d, e, frmt % [rdLoc(a), rope(getSize(p.config, t) * 8),
|
||||
getSimpleTypeDesc(p.module, e.typ)])
|
||||
|
||||
|
||||
case op
|
||||
of mNot:
|
||||
applyFormat("!($1)")
|
||||
of mUnaryPlusI:
|
||||
applyFormat("$1")
|
||||
of mBitnotI:
|
||||
applyFormat("($3)((NU$2) ~($1))")
|
||||
of mUnaryPlusF64:
|
||||
applyFormat("$1")
|
||||
of mUnaryMinusF64:
|
||||
applyFormat("-($1)")
|
||||
of mAbsF64:
|
||||
applyFormat("($1 < 0? -($1) : ($1))")
|
||||
# BUGFIX: fabs() makes problems for Tiny C
|
||||
of mZe8ToI:
|
||||
applyFormat("(($3)(NU)(NU8)($1))")
|
||||
of mZe8ToI64:
|
||||
applyFormat("(($3)(NU64)(NU8)($1))")
|
||||
of mZe16ToI:
|
||||
applyFormat("(($3)(NU)(NU16)($1))")
|
||||
of mZe16ToI64:
|
||||
applyFormat("(($3)(NU64)(NU16)($1))")
|
||||
of mZe32ToI64:
|
||||
applyFormat("(($3)(NU64)(NU32)($1))")
|
||||
of mZeIToI64:
|
||||
applyFormat("(($3)(NU64)(NU)($1))")
|
||||
of mToU8:
|
||||
applyFormat("(($3)(NU8)(NU)($1))")
|
||||
of mToU16:
|
||||
applyFormat("(($3)(NU16)(NU)($1))")
|
||||
of mToU32:
|
||||
applyFormat("(($3)(NU32)(NU64)($1))")
|
||||
of mToFloat:
|
||||
applyFormat("((double) ($1))")
|
||||
of mToBiggestFloat:
|
||||
applyFormat("((double) ($1))")
|
||||
of mToInt:
|
||||
applyFormat("float64ToInt32($1)")
|
||||
of mToBiggestInt:
|
||||
applyFormat("float64ToInt64($1)")
|
||||
else:
|
||||
assert false, $op
|
||||
|
||||
|
||||
|
||||
proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
|
||||
result = p.module.compileToCpp and
|
||||
skipTypes(typ, abstractInstOwned).kind == tyVar and
|
||||
@@ -942,6 +996,23 @@ proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
|
||||
of tyTuple: genTupleElem(p, n, d)
|
||||
else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
|
||||
|
||||
proc isSimpleExpr(n: PNode): bool =
|
||||
# calls all the way down --> can stay expression based
|
||||
case n.kind
|
||||
of nkCallKinds, nkDotExpr, nkPar, nkTupleConstr,
|
||||
nkObjConstr, nkBracket, nkCurly, nkHiddenDeref, nkDerefExpr, nkHiddenAddr,
|
||||
nkHiddenStdConv, nkHiddenSubConv, nkConv, nkAddr:
|
||||
for c in n:
|
||||
if not isSimpleExpr(c): return false
|
||||
result = true
|
||||
of nkStmtListExpr:
|
||||
for i in 0..n.len-2:
|
||||
if n[i].kind notin {nkCommentStmt, nkEmpty}: return false
|
||||
result = isSimpleExpr(n.lastSon)
|
||||
else:
|
||||
if n.isAtom:
|
||||
result = true
|
||||
|
||||
proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
# how to generate code?
|
||||
# 'expr1 and expr2' becomes:
|
||||
@@ -963,24 +1034,41 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
# tmp = a
|
||||
# end:
|
||||
# a = tmp
|
||||
var
|
||||
L: TLabel
|
||||
tmp: TLoc
|
||||
getTemp(p, e.typ, tmp) # force it into a temp!
|
||||
inc p.splitDecls
|
||||
expr(p, e.sons[1], tmp)
|
||||
L = getLabel(p)
|
||||
if m == mOr:
|
||||
lineF(p, cpsStmts, "if ($1) goto $2;$n", [rdLoc(tmp), L])
|
||||
when false:
|
||||
#if isSimpleExpr(e) and p.module.compileToCpp:
|
||||
var tmpA, tmpB: TLoc
|
||||
#getTemp(p, e.typ, tmpA)
|
||||
#getTemp(p, e.typ, tmpB)
|
||||
initLocExprSingleUse(p, e.sons[1], tmpA)
|
||||
initLocExprSingleUse(p, e.sons[2], tmpB)
|
||||
tmpB.k = locExpr
|
||||
if m == mOr:
|
||||
tmpB.r = "((" & rdLoc(tmpA) & ")||(" & rdLoc(tmpB) & "))"
|
||||
else:
|
||||
tmpB.r = "((" & rdLoc(tmpA) & ")&&(" & rdLoc(tmpB) & "))"
|
||||
if d.k == locNone:
|
||||
d = tmpB
|
||||
else:
|
||||
genAssignment(p, d, tmpB, {})
|
||||
else:
|
||||
lineF(p, cpsStmts, "if (!($1)) goto $2;$n", [rdLoc(tmp), L])
|
||||
expr(p, e.sons[2], tmp)
|
||||
fixLabel(p, L)
|
||||
if d.k == locNone:
|
||||
d = tmp
|
||||
else:
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
dec p.splitDecls
|
||||
var
|
||||
L: TLabel
|
||||
tmp: TLoc
|
||||
getTemp(p, e.typ, tmp) # force it into a temp!
|
||||
inc p.splitDecls
|
||||
expr(p, e.sons[1], tmp)
|
||||
L = getLabel(p)
|
||||
if m == mOr:
|
||||
lineF(p, cpsStmts, "if ($1) goto $2;$n", [rdLoc(tmp), L])
|
||||
else:
|
||||
lineF(p, cpsStmts, "if (!($1)) goto $2;$n", [rdLoc(tmp), L])
|
||||
expr(p, e.sons[2], tmp)
|
||||
fixLabel(p, L)
|
||||
if d.k == locNone:
|
||||
d = tmp
|
||||
else:
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
dec p.splitDecls
|
||||
|
||||
proc genEcho(p: BProc, n: PNode) =
|
||||
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
||||
@@ -1675,7 +1763,7 @@ proc fewCmps(conf: ConfigRef; s: PNode): bool =
|
||||
else:
|
||||
result = sonsLen(s) <= 8 # 8 seems to be a good value
|
||||
|
||||
proc binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
|
||||
template binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
|
||||
putIntoDest(p, d, e, frmt % [rdLoc(a), rdSetElemLoc(p.config, b, a.t)])
|
||||
|
||||
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
|
||||
@@ -1686,7 +1774,7 @@ proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
|
||||
of 8: binaryExprIn(p, e, a, b, d, "(($1 &((NU64)1<<((NU)($2)&63U)))!=0)")
|
||||
else: binaryExprIn(p, e, a, b, d, "(($1[(NU)($2)>>3] &(1U<<((NU)($2)&7U)))!=0)")
|
||||
|
||||
proc binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) =
|
||||
template binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) =
|
||||
var a, b: TLoc
|
||||
assert(d.k == locNone)
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
@@ -1753,13 +1841,19 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of 1, 2, 4, 8:
|
||||
case op
|
||||
of mIncl:
|
||||
var ts = "NU" & $(size * 8)
|
||||
binaryStmtInExcl(p, e, d,
|
||||
"$1 |= ((" & ts & ")1)<<(($2)%(sizeof(" & ts & ")*8));$n")
|
||||
case size
|
||||
of 1: binaryStmtInExcl(p, e, d, "$1 |= ((NU8)1)<<(($2) & 7);$n")
|
||||
of 2: binaryStmtInExcl(p, e, d, "$1 |= ((NU16)1)<<(($2) & 15);$n")
|
||||
of 4: binaryStmtInExcl(p, e, d, "$1 |= ((NU32)1)<<(($2) & 31);$n")
|
||||
of 8: binaryStmtInExcl(p, e, d, "$1 |= ((NU64)1)<<(($2) & 63);$n")
|
||||
else: assert(false, $size)
|
||||
of mExcl:
|
||||
var ts = "NU" & $(size * 8)
|
||||
binaryStmtInExcl(p, e, d, "$1 &= ~(((" & ts & ")1) << (($2) % (sizeof(" &
|
||||
ts & ")*8)));$n")
|
||||
case size
|
||||
of 1: binaryStmtInExcl(p, e, d, "$1 &= ~(((NU8)1) << (($2) & 7));$n")
|
||||
of 2: binaryStmtInExcl(p, e, d, "$1 &= ~(((NU16)1) << (($2) & 15));$n")
|
||||
of 4: binaryStmtInExcl(p, e, d, "$1 &= ~(((NU32)1) << (($2) & 31));$n")
|
||||
of 8: binaryStmtInExcl(p, e, d, "$1 &= ~(((NU64)1) << (($2) & 63));$n")
|
||||
else: assert(false, $size)
|
||||
of mCard:
|
||||
if size <= 4: unaryExprChar(p, e, d, "#countBits32($1)")
|
||||
else: unaryExprChar(p, e, d, "#countBits64($1)")
|
||||
@@ -1824,14 +1918,14 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
let etyp = skipTypes(e.typ, abstractRange+{tyOwned})
|
||||
let srcTyp = skipTypes(e.sons[1].typ, abstractRange)
|
||||
if etyp.kind in ValueTypes and lfIndirect notin a.flags:
|
||||
putIntoDest(p, d, e, "(*($1*) ($2))" %
|
||||
[getTypeDesc(p.module, e.typ), addrLoc(p.config, a)], a.storage)
|
||||
elif etyp.kind == tyProc and etyp.callConv == ccClosure:
|
||||
elif etyp.kind == tyProc and etyp.callConv == ccClosure and srcTyp.callConv != ccClosure:
|
||||
putIntoDest(p, d, e, "(($1) ($2))" %
|
||||
[getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)], a.storage)
|
||||
else:
|
||||
let srcTyp = skipTypes(e.sons[1].typ, abstractRange)
|
||||
# C++ does not like direct casts from pointer to shorter integral types
|
||||
if srcTyp.kind in {tyPtr, tyPointer} and etyp.kind in IntegralTypes:
|
||||
putIntoDest(p, d, e, "(($1) (ptrdiff_t) ($2))" %
|
||||
@@ -2085,7 +2179,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)")
|
||||
of mFloatToStr: genDollar(p, e, d, "#nimFloatToStr($1)")
|
||||
of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
|
||||
of mStrToStr: expr(p, e.sons[1], d)
|
||||
of mStrToStr, mUnown: expr(p, e.sons[1], d)
|
||||
of mEnumToStr:
|
||||
if optNimV2 in p.config.globalOptions:
|
||||
genEnumToStr(p, e, d)
|
||||
@@ -2228,14 +2322,14 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
initLocExpr(p, it.sons[0], a)
|
||||
initLocExpr(p, it.sons[1], b)
|
||||
lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
|
||||
"$2 |=((" & ts & ")(1)<<(($1)%(sizeof(" & ts & ")*8)));$n", [
|
||||
"$2 |=(($5)(1)<<(($1)%(sizeof($5)*8)));$n", [
|
||||
rdLoc(idx), rdLoc(d), rdSetElemLoc(p.config, a, e.typ),
|
||||
rdSetElemLoc(p.config, b, e.typ)])
|
||||
rdSetElemLoc(p.config, b, e.typ), rope(ts)])
|
||||
else:
|
||||
initLocExpr(p, it, a)
|
||||
lineF(p, cpsStmts,
|
||||
"$1 |=((" & ts & ")(1)<<(($2)%(sizeof(" & ts & ")*8)));$n",
|
||||
[rdLoc(d), rdSetElemLoc(p.config, a, e.typ)])
|
||||
"$1 |=(($3)(1)<<(($2)%(sizeof($3)*8)));$n",
|
||||
[rdLoc(d), rdSetElemLoc(p.config, a, e.typ), rope(ts)])
|
||||
|
||||
proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||
var rec: TLoc
|
||||
@@ -2609,7 +2703,10 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
genProc(p.module, prc)
|
||||
of nkParForStmt: genParForStmt(p, n)
|
||||
of nkState: genState(p, n)
|
||||
of nkGotoState: genGotoState(p, n)
|
||||
of nkGotoState:
|
||||
# simply never set it back to 0 here from here on...
|
||||
inc p.splitDecls
|
||||
genGotoState(p, n)
|
||||
of nkBreakState: genBreakState(p, n, d)
|
||||
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||
let tryStmt = p.nestedTryStmts.pop
|
||||
if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
|
||||
# Pop safe points generated by try
|
||||
if not tryStmt.inExcept and not isDefined(p.config, "nimQuirky"):
|
||||
if not tryStmt.inExcept:
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n", [])
|
||||
|
||||
# Pop this try-stmt of the list of nested trys
|
||||
@@ -227,8 +227,9 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||
if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
|
||||
# Pop exceptions that was handled by the
|
||||
# except-blocks we are in
|
||||
for i in countdown(howManyExcepts-1, 0):
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||
if not p.noSafePoints:
|
||||
for i in countdown(howManyExcepts-1, 0):
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||
|
||||
proc genGotoState(p: BProc, n: PNode) =
|
||||
# we resist the temptation to translate it into duff's device as it later
|
||||
@@ -449,7 +450,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
|
||||
blockLeaveActions(p,
|
||||
howManyTrys = p.nestedTryStmts.len,
|
||||
howManyExcepts = p.inExceptBlockLen)
|
||||
if (p.finallySafePoints.len > 0) and not isDefined(p.config, "nimQuirky"):
|
||||
if (p.finallySafePoints.len > 0) and not p.noSafePoints:
|
||||
# If we're in a finally block, and we came here by exception
|
||||
# consume it before we return.
|
||||
var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
|
||||
@@ -1004,6 +1005,8 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
(t.kind == nkHiddenTryStmt and sfSystemModule in p.module.module.flags)
|
||||
if not quirkyExceptions:
|
||||
p.module.includeHeader("<setjmp.h>")
|
||||
else:
|
||||
p.noSafePoints = true
|
||||
genLineDir(p, t)
|
||||
discard cgsym(p.module, "Exception")
|
||||
var safePoint: Rope
|
||||
@@ -1021,7 +1024,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
|
||||
var length = sonsLen(t)
|
||||
add(p.nestedTryStmts, (t, false))
|
||||
add(p.nestedTryStmts, (t, quirkyExceptions))
|
||||
expr(p, t.sons[0], d)
|
||||
if not quirkyExceptions:
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n", [])
|
||||
@@ -1135,9 +1138,9 @@ proc genAsmStmt(p: BProc, t: PNode) =
|
||||
# work:
|
||||
if p.prc == nil:
|
||||
# top level asm statement?
|
||||
addf(p.module.s[cfsProcHeaders], CC[p.config.cCompiler].asmStmtFrmt, [s])
|
||||
add(p.module.s[cfsProcHeaders], runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s]))
|
||||
else:
|
||||
lineF(p, cpsStmts, CC[p.config.cCompiler].asmStmtFrmt, [s])
|
||||
add(p.s(cpsStmts), indentLine(p, runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s])))
|
||||
|
||||
proc determineSection(n: PNode): TCFileSection =
|
||||
result = cfsProcHeaders
|
||||
|
||||
@@ -338,12 +338,17 @@ proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope =
|
||||
if result == nil: result = cacheGetType(m.typeCache, sig)
|
||||
|
||||
proc structOrUnion(t: PType): Rope =
|
||||
let cachedUnion {.global.} = rope("union")
|
||||
let cachedStruct {.global.} = rope("struct")
|
||||
let t = t.skipTypes({tyAlias, tySink})
|
||||
(if tfUnion in t.flags: rope("union") else: rope("struct"))
|
||||
if tfUnion in t.flags: cachedUnion
|
||||
else: cachedStruct
|
||||
|
||||
proc getForwardStructFormat(m: BModule): string =
|
||||
if m.compileToCpp: result = "$1 $2;$n"
|
||||
else: result = "typedef $1 $2 $2;$n"
|
||||
proc addForwardStructFormat(m: BModule, structOrUnion: Rope, typename: Rope) =
|
||||
if m.compileToCpp:
|
||||
m.s[cfsForwardTypes].addf "$1 $2;$n", [structOrUnion, typename]
|
||||
else:
|
||||
m.s[cfsForwardTypes].addf "typedef $1 $2 $2;$n", [structOrUnion, typename]
|
||||
|
||||
proc seqStar(m: BModule): string =
|
||||
if m.config.selectedGC == gcDestructors: result = ""
|
||||
@@ -360,8 +365,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
|
||||
result = getTypeName(m, typ, sig)
|
||||
m.forwTypeCache[sig] = result
|
||||
if not isImportedType(concrete):
|
||||
addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||
[structOrUnion(typ), result])
|
||||
addForwardStructFormat(m, structOrUnion(typ), result)
|
||||
else:
|
||||
pushType(m, concrete)
|
||||
doAssert m.forwTypeCache[sig] == result
|
||||
@@ -733,8 +737,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||
if result == nil:
|
||||
result = getTypeName(m, origTyp, sig)
|
||||
if not isImportedType(t):
|
||||
addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||
[structOrUnion(t), result])
|
||||
addForwardStructFormat(m, structOrUnion(t), result)
|
||||
m.forwTypeCache[sig] = result
|
||||
assert(cacheGetType(m.typeCache, sig) == nil)
|
||||
m.typeCache[sig] = result & seqStar(m)
|
||||
@@ -845,8 +848,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||
result = getTypeName(m, origTyp, sig)
|
||||
m.forwTypeCache[sig] = result
|
||||
if not isImportedType(t):
|
||||
addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||
[structOrUnion(t), result])
|
||||
addForwardStructFormat(m, structOrUnion(t), result)
|
||||
assert m.forwTypeCache[sig] == result
|
||||
m.typeCache[sig] = result # always call for sideeffects:
|
||||
if not incompleteType(t):
|
||||
@@ -905,7 +907,8 @@ proc finishTypeDescriptions(m: BModule) =
|
||||
discard getTypeDesc(m, m.typeStack[i])
|
||||
inc(i)
|
||||
|
||||
template cgDeclFrmt*(s: PSym): string = s.constraint.strVal
|
||||
template cgDeclFrmt*(s: PSym): string =
|
||||
s.constraint.strVal
|
||||
|
||||
proc isReloadable(m: BModule, prc: PSym): bool =
|
||||
return m.hcrOn and sfNonReloadable notin prc.flags
|
||||
@@ -943,7 +946,7 @@ proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope =
|
||||
params])
|
||||
else:
|
||||
let asPtrStr = if asPtr: (rope("(*") & name & ")") else: name
|
||||
result = prc.cgDeclFrmt % [rettype, asPtrStr, params]
|
||||
result = runtimeFormat(prc.cgDeclFrmt, [rettype, asPtrStr, params])
|
||||
|
||||
# ------------------ type info generation -------------------------------------
|
||||
|
||||
@@ -1346,10 +1349,10 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
|
||||
# results are not deterministic!
|
||||
genTupleInfo(m, t, origType, result, info)
|
||||
else: internalError(m.config, "genTypeInfo(" & $t.kind & ')')
|
||||
if t.deepCopy != nil:
|
||||
genDeepCopyProc(m, t.deepCopy, result)
|
||||
elif origType.deepCopy != nil:
|
||||
genDeepCopyProc(m, origType.deepCopy, result)
|
||||
if t.attachedOps[attachedDeepCopy] != nil:
|
||||
genDeepCopyProc(m, t.attachedOps[attachedDeepCopy], result)
|
||||
elif origType.attachedOps[attachedDeepCopy] != nil:
|
||||
genDeepCopyProc(m, origType.attachedOps[attachedDeepCopy], result)
|
||||
result = prefixTI.rope & result & ")".rope
|
||||
|
||||
proc genTypeSection(m: BModule, n: PNode) =
|
||||
|
||||
@@ -206,15 +206,15 @@ proc indentLine(p: BProc, r: Rope): Rope =
|
||||
prepend(result, "\t".rope)
|
||||
|
||||
template appcg(m: BModule, c: var Rope, frmt: FormatStr,
|
||||
args: varargs[untyped]) =
|
||||
args: untyped) =
|
||||
add(c, ropecg(m, frmt, args))
|
||||
|
||||
template appcg(m: BModule, sec: TCFileSection, frmt: FormatStr,
|
||||
args: varargs[untyped]) =
|
||||
args: untyped) =
|
||||
add(m.s[sec], ropecg(m, frmt, args))
|
||||
|
||||
template appcg(p: BProc, sec: TCProcSection, frmt: FormatStr,
|
||||
args: varargs[untyped]) =
|
||||
args: untyped) =
|
||||
add(p.s(sec), ropecg(p.module, frmt, args))
|
||||
|
||||
template line(p: BProc, sec: TCProcSection, r: Rope) =
|
||||
@@ -224,7 +224,7 @@ template line(p: BProc, sec: TCProcSection, r: string) =
|
||||
add(p.s(sec), indentLine(p, r.rope))
|
||||
|
||||
template lineF(p: BProc, sec: TCProcSection, frmt: FormatStr,
|
||||
args: openarray[Rope]) =
|
||||
args: untyped) =
|
||||
add(p.s(sec), indentLine(p, frmt % args))
|
||||
|
||||
template lineCg(p: BProc, sec: TCProcSection, frmt: FormatStr,
|
||||
@@ -440,6 +440,15 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||
result.flags = {}
|
||||
constructLoc(p, result, not needsInit)
|
||||
|
||||
proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) =
|
||||
inc(p.labels)
|
||||
result.r = "T" & rope(p.labels) & "_"
|
||||
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t), result.r, value])
|
||||
result.k = locTemp
|
||||
result.lode = lodeTyp t
|
||||
result.storage = OnStack
|
||||
result.flags = {}
|
||||
|
||||
proc getIntTemp(p: BProc, result: var TLoc) =
|
||||
inc(p.labels)
|
||||
result.r = "T" & rope(p.labels) & "_"
|
||||
@@ -484,7 +493,7 @@ proc localVarDecl(p: BProc; n: PNode): Rope =
|
||||
add(result, " ")
|
||||
add(result, s.loc.r)
|
||||
else:
|
||||
result = s.cgDeclFrmt % [result, s.loc.r]
|
||||
result = runtimeFormat(s.cgDeclFrmt, [result, s.loc.r])
|
||||
|
||||
proc assignLocalVar(p: BProc, n: PNode) =
|
||||
#assert(s.loc.k == locNone) # not yet assigned
|
||||
@@ -535,7 +544,7 @@ proc assignGlobalVar(p: BProc, n: PNode) =
|
||||
if sfVolatile in s.flags: add(decl, " volatile")
|
||||
addf(decl, " $1;$n", [s.loc.r])
|
||||
else:
|
||||
decl = (s.cgDeclFrmt & ";$n") % [td, s.loc.r]
|
||||
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
|
||||
add(p.module.s[cfsVars], decl)
|
||||
if p.withinLoop > 0:
|
||||
# fixes tests/run/tzeroarray:
|
||||
|
||||
@@ -70,6 +70,7 @@ type
|
||||
threadVarAccessed*: bool # true if the proc already accessed some threadvar
|
||||
hasCurFramePointer*: bool # true if _nimCurFrame var needed to recover after
|
||||
# exception is generated
|
||||
noSafePoints*: bool # the proc doesn't use safe points in exception handling
|
||||
lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements
|
||||
currLineInfo*: TLineInfo # AST codegen will make this superfluous
|
||||
nestedTryStmts*: seq[tuple[n: PNode, inExcept: bool]]
|
||||
|
||||
@@ -567,19 +567,36 @@ proc genReturn(c: var Con; n: PNode) =
|
||||
|
||||
const
|
||||
InterestingSyms = {skVar, skResult, skLet, skParam, skForVar, skTemp}
|
||||
PathKinds* = {nkDotExpr, nkCheckedFieldExpr,
|
||||
PathKinds0 = {nkDotExpr, nkCheckedFieldExpr,
|
||||
nkBracketExpr, nkDerefExpr, nkHiddenDeref,
|
||||
nkAddr, nkHiddenAddr,
|
||||
nkHiddenStdConv, nkHiddenSubConv, nkObjDownConv, nkObjUpConv}
|
||||
nkObjDownConv, nkObjUpConv}
|
||||
PathKinds1 = {nkHiddenStdConv, nkHiddenSubConv}
|
||||
|
||||
proc getRoot(n: PNode): PNode =
|
||||
result = n
|
||||
while true:
|
||||
case result.kind
|
||||
of PathKinds0:
|
||||
result = result[0]
|
||||
of PathKinds1:
|
||||
result = result[1]
|
||||
else: break
|
||||
|
||||
proc skipConvDfa*(n: PNode): PNode =
|
||||
result = n
|
||||
while true:
|
||||
case result.kind
|
||||
of nkObjDownConv, nkObjUpConv:
|
||||
result = result[0]
|
||||
of PathKinds1:
|
||||
result = result[1]
|
||||
else: break
|
||||
|
||||
proc genUse(c: var Con; orig: PNode) =
|
||||
var n = orig
|
||||
var iters = 0
|
||||
while n.kind in PathKinds:
|
||||
n = n[0]
|
||||
inc iters
|
||||
let n = dfa.getRoot(orig)
|
||||
if n.kind == nkSym and n.sym.kind in InterestingSyms:
|
||||
c.code.add Instr(n: orig, kind: use, sym: if iters > 0: nil else: n.sym)
|
||||
c.code.add Instr(n: orig, kind: use, sym: if orig != n: nil else: n.sym)
|
||||
|
||||
proc aliases(obj, field: PNode): bool =
|
||||
var n = field
|
||||
@@ -590,7 +607,7 @@ proc aliases(obj, field: PNode): bool =
|
||||
if sameTrees(obj, n): return true
|
||||
case n.kind
|
||||
of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv,
|
||||
nkObjDownConv, nkObjUpConv, nkHiddenDeref:
|
||||
nkObjDownConv, nkObjUpConv, nkHiddenDeref, nkDerefExpr:
|
||||
n = n[0]
|
||||
of nkBracketExpr:
|
||||
let x = n[0]
|
||||
@@ -616,13 +633,19 @@ proc instrTargets*(ins: Instr; loc: PNode): bool =
|
||||
# use x; question does it affect 'x.f'? Yes.
|
||||
result = aliases(ins.n, loc) or aliases(loc, ins.n)
|
||||
|
||||
proc isAnalysableFieldAccess*(n: PNode; owner: PSym): bool =
|
||||
var n = n
|
||||
proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool =
|
||||
var n = orig
|
||||
while true:
|
||||
case n.kind
|
||||
of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv,
|
||||
nkObjDownConv, nkObjUpConv, nkHiddenDeref:
|
||||
nkObjDownConv, nkObjUpConv:
|
||||
n = n[0]
|
||||
of nkHiddenDeref, nkDerefExpr:
|
||||
# We "own" sinkparam[].loc but not ourVar[].location as it is a nasty
|
||||
# pointer indirection.
|
||||
n = n[0]
|
||||
return n.kind == nkSym and n.sym.owner == owner and (isSinkParam(n.sym) or
|
||||
n.sym.typ.skipTypes(abstractInst-{tyOwned}).kind in {tyOwned, tyVar})
|
||||
of nkBracketExpr:
|
||||
let x = n[0]
|
||||
if x.typ != nil and x.typ.skipTypes(abstractInst).kind == tyTuple:
|
||||
@@ -633,11 +656,25 @@ proc isAnalysableFieldAccess*(n: PNode; owner: PSym): bool =
|
||||
break
|
||||
# XXX Allow closure deref operations here if we know
|
||||
# the owner controlled the closure allocation?
|
||||
result = n.kind == nkSym and n.sym.owner == owner and owner.kind != skModule
|
||||
result = n.kind == nkSym and n.sym.owner == owner and
|
||||
owner.kind != skModule and
|
||||
(n.sym.kind != skParam or isSinkParam(n.sym)) # or n.sym.typ.kind == tyVar)
|
||||
# Note: There is a different move analyzer possible that checks for
|
||||
# consume(param.key); param.key = newValue for all paths. Then code like
|
||||
#
|
||||
# let splited = split(move self.root, x)
|
||||
# self.root = merge(splited.lower, splited.greater)
|
||||
#
|
||||
# could be written without the ``move self.root``. However, this would be
|
||||
# wrong! Then the write barrier for the ``self.root`` assignment would
|
||||
# free the old data and all is lost! Lesson: Don't be too smart, trust the
|
||||
# lower level C++ optimizer to specialize this code.
|
||||
|
||||
proc genDef(c: var Con; n: PNode) =
|
||||
if n.kind == nkSym and n.sym.kind in InterestingSyms:
|
||||
c.code.add Instr(n: n, kind: def, sym: n.sym)
|
||||
elif isAnalysableFieldAccess(n, c.owner):
|
||||
c.code.add Instr(n: n, kind: def, sym: nil)
|
||||
|
||||
proc canRaise(fn: PNode): bool =
|
||||
const magicsThatCanRaise = {
|
||||
@@ -715,7 +752,7 @@ proc gen(c: var Con; n: PNode) =
|
||||
# "uses" 'i'. But we are only talking about builtin array indexing so
|
||||
# it doesn't matter and 'x = 34' is NOT a usage of 'x'.
|
||||
genDef(c, n[0])
|
||||
of PathKinds:
|
||||
of PathKinds0 - {nkHiddenStdConv, nkHiddenSubConv, nkObjDownConv, nkObjUpConv}:
|
||||
genUse(c, n)
|
||||
of nkIfStmt, nkIfExpr: genIf(c, n)
|
||||
of nkWhenStmt:
|
||||
@@ -732,8 +769,8 @@ proc gen(c: var Con; n: PNode) =
|
||||
nkBracket, nkCurly, nkPar, nkTupleConstr, nkClosure, nkObjConstr:
|
||||
for x in n: gen(c, x)
|
||||
of nkPragmaBlock: gen(c, n.lastSon)
|
||||
of nkDiscardStmt: gen(c, n.sons[0])
|
||||
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast:
|
||||
of nkDiscardStmt, nkObjDownConv, nkObjUpConv: gen(c, n.sons[0])
|
||||
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, nkHiddenSubConv, nkHiddenStdConv:
|
||||
gen(c, n.sons[1])
|
||||
of nkStringToCString, nkCStringToString: gen(c, n.sons[0])
|
||||
of nkVarSection, nkLetSection: genVarSection(c, n)
|
||||
|
||||
@@ -172,7 +172,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
|
||||
outExt, RelativeDir"htmldocs", false)
|
||||
result.thisDir = result.destFile.splitFile.dir
|
||||
|
||||
proc dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) =
|
||||
template dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) =
|
||||
if conf.cmd != cmdRst2tex: addf(dest, xml, args)
|
||||
else: addf(dest, tex, args)
|
||||
|
||||
|
||||
@@ -20,11 +20,12 @@ type
|
||||
TGen = object of PPassContext
|
||||
doc: PDoc
|
||||
module: PSym
|
||||
config: ConfigRef
|
||||
PGen = ref TGen
|
||||
|
||||
template shouldProcess(g): bool =
|
||||
(g.module.owner.id == g.doc.conf.mainPackageId and optWholeProject in g.doc.conf.globalOptions) or
|
||||
sfMainModule in g.module.flags
|
||||
sfMainModule in g.module.flags or g.config.projectMainIdx == g.module.info.fileIndex
|
||||
|
||||
template closeImpl(body: untyped) {.dirty.} =
|
||||
var g = PGen(p)
|
||||
@@ -60,6 +61,7 @@ template myOpenImpl(ext: untyped) {.dirty.} =
|
||||
var g: PGen
|
||||
new(g)
|
||||
g.module = module
|
||||
g.config = graph.config
|
||||
var d = newDocumentor(AbsoluteFile toFullPath(graph.config, FileIndex module.position),
|
||||
graph.cache, graph.config, ext)
|
||||
d.hasToc = true
|
||||
|
||||
@@ -376,7 +376,7 @@ proc nameToCC*(name: string): TSystemCC =
|
||||
result = ccNone
|
||||
|
||||
proc isVSCompatible*(conf: ConfigRef): bool =
|
||||
return conf.cCompiler == ccVcc or
|
||||
return conf.cCompiler == ccVcc or
|
||||
conf.cCompiler == ccClangCl or
|
||||
(conf.cCompiler == ccIcl and conf.target.hostOS in osDos..osWindows)
|
||||
|
||||
@@ -738,7 +738,7 @@ proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile,
|
||||
# way of being able to debug and rebuild the program at the same time. This
|
||||
# is accomplished using the /PDB:<filename> flag (there also exists the
|
||||
# /PDBALTPATH:<filename> flag). The only downside is that the .pdb files are
|
||||
# atleast 300kb big (when linking statically to the runtime - or else 5mb+)
|
||||
# atleast 300kb big (when linking statically to the runtime - or else 5mb+)
|
||||
# and will quickly accumulate. There is a hacky solution: we could try to
|
||||
# delete all .pdb files with a pattern and swallow exceptions.
|
||||
#
|
||||
@@ -910,7 +910,8 @@ proc callCCompiler*(conf: ConfigRef) =
|
||||
else: AbsoluteFile(conf.projectName)
|
||||
linkCmd = getLinkCmd(conf, mainOutput, objfiles)
|
||||
if optCompileOnly notin conf.globalOptions:
|
||||
if defined(windows) and linkCmd.len > 8_000:
|
||||
const MaxCmdLen = when defined(windows): 8_000 else: 32_000
|
||||
if linkCmd.len > MaxCmdLen:
|
||||
# Windows's command line limit is about 8K (don't laugh...) so C compilers on
|
||||
# Windows support a feature where the command line can be passed via ``@linkcmd``
|
||||
# to them.
|
||||
|
||||
@@ -136,7 +136,7 @@ to do it.
|
||||
import
|
||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
||||
strutils, options, dfa, lowerings, tables, modulegraphs, msgs,
|
||||
lineinfos, parampatterns
|
||||
lineinfos, parampatterns, sighashes
|
||||
|
||||
const
|
||||
InterestingSyms = {skVar, skResult, skLet, skForVar, skTemp}
|
||||
@@ -195,15 +195,17 @@ proc isLastRead(n: PNode; c: var Con): bool =
|
||||
# first we need to search for the instruction that belongs to 'n':
|
||||
c.otherRead = nil
|
||||
var instr = -1
|
||||
let m = dfa.skipConvDfa(n)
|
||||
|
||||
for i in 0..<c.g.len:
|
||||
# This comparison is correct and MUST not be ``instrTargets``:
|
||||
if c.g[i].kind == use and c.g[i].n == n:
|
||||
if c.g[i].kind == use and c.g[i].n == m:
|
||||
if instr < 0:
|
||||
instr = i
|
||||
break
|
||||
|
||||
dbg:
|
||||
echo "starting point for ", n, " is ", instr
|
||||
echo "starting point for ", n, " is ", instr, " ", n.kind
|
||||
|
||||
if instr < 0: return false
|
||||
# we go through all paths beginning from 'instr+1' and need to
|
||||
@@ -314,24 +316,37 @@ proc makePtrType(c: Con, baseType: PType): PType =
|
||||
result = newType(tyPtr, c.owner)
|
||||
addSonSkipIntLit(result, baseType)
|
||||
|
||||
template genOp(opr, opname, ri) =
|
||||
let op = opr
|
||||
proc addDestroy(c: var Con; n: PNode) =
|
||||
# append to front:
|
||||
c.destroys = newTree(nkStmtList, n, c.destroys)
|
||||
|
||||
proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
|
||||
var op = t.attachedOps[kind]
|
||||
|
||||
if op == nil:
|
||||
globalError(c.graph.config, dest.info, "internal error: '" & opname &
|
||||
# give up and find the canonical type instead:
|
||||
let h = sighashes.hashType(t, {CoType, CoConsiderOwned})
|
||||
let canon = c.graph.canonTypes.getOrDefault(h)
|
||||
if canon != nil:
|
||||
op = canon.attachedOps[kind]
|
||||
|
||||
if op == nil:
|
||||
globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] &
|
||||
"' operator not found for type " & typeToString(t))
|
||||
elif op.ast[genericParamsPos].kind != nkEmpty:
|
||||
globalError(c.graph.config, dest.info, "internal error: '" & opname &
|
||||
globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] &
|
||||
"' operator is generic")
|
||||
if sfError in op.flags: checkForErrorPragma(c, t, ri, opname)
|
||||
if sfError in op.flags: checkForErrorPragma(c, t, ri, AttachedOpToStr[kind])
|
||||
let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
|
||||
addrExp.add(dest)
|
||||
result = newTree(nkCall, newSymNode(op), addrExp)
|
||||
|
||||
proc genSink(c: Con; t: PType; dest, ri: PNode): PNode =
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
let op = if t.sink != nil: t.sink else: t.assignment
|
||||
if op != nil:
|
||||
genOp(op, "=sink", ri)
|
||||
let k = if t.attachedOps[attachedSink] != nil: attachedSink
|
||||
else: attachedAsgn
|
||||
if t.attachedOps[k] != nil:
|
||||
result = genOp(c, t, k, dest, ri)
|
||||
else:
|
||||
# in rare cases only =destroy exists but no sink or assignment
|
||||
# (see Pony object in tmove_objconstr.nim)
|
||||
@@ -342,15 +357,15 @@ proc genCopy(c: Con; t: PType; dest, ri: PNode): PNode =
|
||||
if tfHasOwned in t.flags:
|
||||
checkForErrorPragma(c, t, ri, "=")
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
genOp(t.assignment, "=", ri)
|
||||
result = genOp(c, t, attachedAsgn, dest, ri)
|
||||
|
||||
proc genCopyNoCheck(c: Con; t: PType; dest, ri: PNode): PNode =
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
genOp(t.assignment, "=", ri)
|
||||
result = genOp(c, t, attachedAsgn, dest, ri)
|
||||
|
||||
proc genDestroy(c: Con; t: PType; dest: PNode): PNode =
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
genOp(t.destructor, "=destroy", nil)
|
||||
result = genOp(c, t, attachedDestructor, dest, nil)
|
||||
|
||||
proc addTopVar(c: var Con; v: PNode) =
|
||||
c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode)
|
||||
@@ -408,6 +423,17 @@ proc sinkParamIsLastReadCheck(c: var Con, s: PNode) =
|
||||
localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s &
|
||||
"` is already consumed at " & toFileLineCol(c. graph.config, s.info))
|
||||
|
||||
proc isSinkTypeForParam(t: PType): bool =
|
||||
# a parameter like 'seq[owned T]' must not be used only once, but its
|
||||
# elements must, so we detect this case here:
|
||||
result = t.skipTypes({tyGenericInst, tyAlias}).kind in {tySink, tyOwned}
|
||||
when false:
|
||||
if isSinkType(t):
|
||||
if t.skipTypes({tyGenericInst, tyAlias}).kind in {tyArray, tyVarargs, tyOpenArray, tySequence}:
|
||||
result = false
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc passCopyToSink(n: PNode; c: var Con): PNode =
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
let tmp = getTemp(c, n.typ, n.info)
|
||||
@@ -441,7 +467,7 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||
let L = if parameters != nil: parameters.len else: 0
|
||||
result.add arg[0]
|
||||
for i in 1..<arg.len:
|
||||
result.add pArg(arg[i], c, i < L and isSinkType(parameters[i]))
|
||||
result.add pArg(arg[i], c, i < L and isSinkTypeForParam(parameters[i]))
|
||||
elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkBracket, nkCharLit..nkTripleStrLit}:
|
||||
discard "object construction to sink parameter: nothing to do"
|
||||
result = arg
|
||||
@@ -518,16 +544,22 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||
let L = if parameters != nil: parameters.len else: 0
|
||||
ri2.add ri[0]
|
||||
for i in 1..<ri.len:
|
||||
ri2.add pArg(ri[i], c, i < L and isSinkType(parameters[i]))
|
||||
ri2.add pArg(ri[i], c, i < L and isSinkTypeForParam(parameters[i]))
|
||||
#recurse(ri, ri2)
|
||||
result.add ri2
|
||||
of nkBracketExpr:
|
||||
if ri[0].kind == nkSym and isUnpackedTuple(ri[0].sym):
|
||||
# unpacking of tuple: move out the elements
|
||||
result = genSink(c, dest.typ, dest, ri)
|
||||
result.add p(ri, c)
|
||||
elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
var snk = genSink(c, dest.typ, dest, ri)
|
||||
snk.add ri
|
||||
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
|
||||
else:
|
||||
result = genCopy(c, dest.typ, dest, ri)
|
||||
result.add p(ri, c)
|
||||
result.add p(ri, c)
|
||||
of nkStmtListExpr:
|
||||
result = newNodeI(nkStmtList, ri.info)
|
||||
for i in 0..ri.len-2:
|
||||
@@ -610,7 +642,9 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||
result = genCopy(c, dest.typ, dest, ri)
|
||||
result.add p(ri, c)
|
||||
of nkHiddenSubConv, nkHiddenStdConv:
|
||||
if ri[1].kind in movableNodeKinds:
|
||||
if sameType(ri.typ, ri[1].typ):
|
||||
result = moveOrCopy(dest, ri[1], c)
|
||||
elif ri[1].kind in movableNodeKinds:
|
||||
result = moveOrCopy(dest, ri[1], c)
|
||||
var b = newNodeIT(ri.kind, ri.info, ri.typ)
|
||||
b.add ri[0] # add empty node
|
||||
@@ -673,6 +707,15 @@ proc injectDefaultCalls(n: PNode, c: var Con) =
|
||||
proc isCursor(n: PNode): bool {.inline.} =
|
||||
result = n.kind == nkSym and sfCursor in n.sym.flags
|
||||
|
||||
proc keepVar(n, it: PNode, c: var Con): PNode =
|
||||
# keep the var but transform 'ri':
|
||||
result = copyNode(n)
|
||||
var itCopy = copyNode(it)
|
||||
for j in 0..it.len-2:
|
||||
itCopy.add it[j]
|
||||
itCopy.add p(it[it.len-1], c)
|
||||
result.add itCopy
|
||||
|
||||
proc p(n: PNode; c: var Con): PNode =
|
||||
case n.kind
|
||||
of nkVarSection, nkLetSection:
|
||||
@@ -694,24 +737,17 @@ proc p(n: PNode; c: var Con): PNode =
|
||||
c.addTopVar v
|
||||
# make sure it's destroyed at the end of the proc:
|
||||
if not isUnpackedTuple(it[0].sym):
|
||||
c.destroys.add genDestroy(c, v.typ, v)
|
||||
if ri.kind != nkEmpty:
|
||||
let r = moveOrCopy(v, ri, c)
|
||||
result.add r
|
||||
c.addDestroy genDestroy(c, v.typ, v)
|
||||
if ri.kind != nkEmpty:
|
||||
let r = moveOrCopy(v, ri, c)
|
||||
result.add r
|
||||
else:
|
||||
# keep it, but transform 'ri':
|
||||
var varSection = copyNode(n)
|
||||
var itCopy = copyNode(it)
|
||||
for j in 0..L-2:
|
||||
itCopy.add it[j]
|
||||
itCopy.add p(ri, c)
|
||||
varSection.add itCopy
|
||||
result.add varSection
|
||||
result.add keepVar(n, it, c)
|
||||
of nkCallKinds:
|
||||
let parameters = n[0].typ
|
||||
let L = if parameters != nil: parameters.len else: 0
|
||||
for i in 1 ..< n.len:
|
||||
n.sons[i] = pArg(n[i], c, i < L and isSinkType(parameters[i]))
|
||||
n.sons[i] = pArg(n[i], c, i < L and isSinkTypeForParam(parameters[i]))
|
||||
if n.typ != nil and hasDestructor(n.typ):
|
||||
discard "produce temp creation"
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
@@ -720,11 +756,11 @@ proc p(n: PNode; c: var Con): PNode =
|
||||
sinkExpr.add n
|
||||
result.add sinkExpr
|
||||
result.add tmp
|
||||
c.destroys.add genDestroy(c, n.typ, tmp)
|
||||
c.addDestroy genDestroy(c, n.typ, tmp)
|
||||
else:
|
||||
result = n
|
||||
of nkAsgn, nkFastAsgn:
|
||||
if hasDestructor(n[0].typ):
|
||||
if hasDestructor(n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda, nkClosure}:
|
||||
result = moveOrCopy(n[0], n[1], c)
|
||||
else:
|
||||
result = copyNode(n)
|
||||
@@ -783,8 +819,8 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
|
||||
let params = owner.typ.n
|
||||
for i in 1 ..< params.len:
|
||||
let param = params[i].sym
|
||||
if isSinkParam(param) and hasDestructor(param.typ.skipTypes({tySink})):
|
||||
c.destroys.add genDestroy(c, param.typ.skipTypes({tyGenericInst, tyAlias, tySink}), params[i])
|
||||
if isSinkTypeForParam(param.typ) and hasDestructor(param.typ.skipTypes({tySink})):
|
||||
c.addDestroy genDestroy(c, param.typ.skipTypes({tyGenericInst, tyAlias, tySink}), params[i])
|
||||
|
||||
#if optNimV2 in c.graph.config.globalOptions:
|
||||
# injectDefaultCalls(n, c)
|
||||
|
||||
@@ -32,9 +32,9 @@ import
|
||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
|
||||
nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os, tables,
|
||||
times, ropes, math, passes, ccgutils, wordrecg, renderer,
|
||||
intsets, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
|
||||
intsets, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
|
||||
pathutils, transf
|
||||
|
||||
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
|
||||
@@ -365,92 +365,92 @@ proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||
line(p, "}")
|
||||
|
||||
type
|
||||
TMagicFrmt = array[0..3, string]
|
||||
TMagicFrmt = array[0..1, string]
|
||||
TMagicOps = array[mAddI..mStrToStr, TMagicFrmt]
|
||||
|
||||
const # magic checked op; magic unchecked op; checked op; unchecked op
|
||||
jsOps: TMagicOps = [
|
||||
["addInt", "", "addInt($1, $2)", "($1 + $2)"], # AddI
|
||||
["subInt", "", "subInt($1, $2)", "($1 - $2)"], # SubI
|
||||
["mulInt", "", "mulInt($1, $2)", "($1 * $2)"], # MulI
|
||||
["divInt", "", "divInt($1, $2)", "Math.trunc($1 / $2)"], # DivI
|
||||
["modInt", "", "modInt($1, $2)", "Math.trunc($1 % $2)"], # ModI
|
||||
["addInt", "", "addInt($1, $2)", "($1 + $2)"], # Succ
|
||||
["subInt", "", "subInt($1, $2)", "($1 - $2)"], # Pred
|
||||
["", "", "($1 + $2)", "($1 + $2)"], # AddF64
|
||||
["", "", "($1 - $2)", "($1 - $2)"], # SubF64
|
||||
["", "", "($1 * $2)", "($1 * $2)"], # MulF64
|
||||
["", "", "($1 / $2)", "($1 / $2)"], # DivF64
|
||||
["", "", "", ""], # ShrI
|
||||
["", "", "($1 << $2)", "($1 << $2)"], # ShlI
|
||||
["", "", "($1 >> $2)", "($1 >> $2)"], # AshrI
|
||||
["", "", "($1 & $2)", "($1 & $2)"], # BitandI
|
||||
["", "", "($1 | $2)", "($1 | $2)"], # BitorI
|
||||
["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI
|
||||
["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI
|
||||
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI
|
||||
["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
|
||||
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
|
||||
["", "", "", ""], # addU
|
||||
["", "", "", ""], # subU
|
||||
["", "", "", ""], # mulU
|
||||
["", "", "", ""], # divU
|
||||
["", "", "($1 % $2)", "($1 % $2)"], # modU
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqI
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # LeI
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # LtI
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqF64
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # LeF64
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # LtF64
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # leU
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # ltU
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # leU64
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # ltU64
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqEnum
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # LeEnum
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # LtEnum
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqCh
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # LeCh
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # LtCh
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqB
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # LeB
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # LtB
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqRef
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqUntracedRef
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # LePtr
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # LtPtr
|
||||
["", "", "($1 != $2)", "($1 != $2)"], # Xor
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqCString
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqProc
|
||||
["negInt", "", "negInt($1)", "-($1)"], # UnaryMinusI
|
||||
["negInt64", "", "negInt64($1)", "-($1)"], # UnaryMinusI64
|
||||
["absInt", "", "absInt($1)", "Math.abs($1)"], # AbsI
|
||||
["", "", "!($1)", "!($1)"], # Not
|
||||
["", "", "+($1)", "+($1)"], # UnaryPlusI
|
||||
["", "", "~($1)", "~($1)"], # BitnotI
|
||||
["", "", "+($1)", "+($1)"], # UnaryPlusF64
|
||||
["", "", "-($1)", "-($1)"], # UnaryMinusF64
|
||||
["", "", "Math.abs($1)", "Math.abs($1)"], # AbsF64
|
||||
["Ze8ToI", "Ze8ToI", "Ze8ToI($1)", "Ze8ToI($1)"], # mZe8ToI
|
||||
["Ze8ToI64", "Ze8ToI64", "Ze8ToI64($1)", "Ze8ToI64($1)"], # mZe8ToI64
|
||||
["Ze16ToI", "Ze16ToI", "Ze16ToI($1)", "Ze16ToI($1)"], # mZe16ToI
|
||||
["Ze16ToI64", "Ze16ToI64", "Ze16ToI64($1)", "Ze16ToI64($1)"], # mZe16ToI64
|
||||
["Ze32ToI64", "Ze32ToI64", "Ze32ToI64($1)", "Ze32ToI64($1)"], # mZe32ToI64
|
||||
["ZeIToI64", "ZeIToI64", "ZeIToI64($1)", "ZeIToI64($1)"], # mZeIToI64
|
||||
["toU8", "toU8", "toU8($1)", "toU8($1)"], # toU8
|
||||
["toU16", "toU16", "toU16($1)", "toU16($1)"], # toU16
|
||||
["toU32", "toU32", "toU32($1)", "toU32($1)"], # toU32
|
||||
["", "", "$1", "$1"], # ToFloat
|
||||
["", "", "$1", "$1"], # ToBiggestFloat
|
||||
["", "", "Math.trunc($1)", "Math.trunc($1)"], # ToInt
|
||||
["", "", "Math.trunc($1)", "Math.trunc($1)"], # ToBiggestInt
|
||||
["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"],
|
||||
["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"],
|
||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
|
||||
["", "", "$1", "$1"]]
|
||||
const # magic checked op; magic unchecked op;
|
||||
jsMagics: TMagicOps = [
|
||||
["addInt", ""], # AddI
|
||||
["subInt", ""], # SubI
|
||||
["mulInt", ""], # MulI
|
||||
["divInt", ""], # DivI
|
||||
["modInt", ""], # ModI
|
||||
["addInt", ""], # Succ
|
||||
["subInt", ""], # Pred
|
||||
["", ""], # AddF64
|
||||
["", ""], # SubF64
|
||||
["", ""], # MulF64
|
||||
["", ""], # DivF64
|
||||
["", ""], # ShrI
|
||||
["", ""], # ShlI
|
||||
["", ""], # AshrI
|
||||
["", ""], # BitandI
|
||||
["", ""], # BitorI
|
||||
["", ""], # BitxorI
|
||||
["nimMin", "nimMin"], # MinI
|
||||
["nimMax", "nimMax"], # MaxI
|
||||
["nimMin", "nimMin"], # MinF64
|
||||
["nimMax", "nimMax"], # MaxF64
|
||||
["", ""], # addU
|
||||
["", ""], # subU
|
||||
["", ""], # mulU
|
||||
["", ""], # divU
|
||||
["", ""], # modU
|
||||
["", ""], # EqI
|
||||
["", ""], # LeI
|
||||
["", ""], # LtI
|
||||
["", ""], # EqF64
|
||||
["", ""], # LeF64
|
||||
["", ""], # LtF64
|
||||
["", ""], # leU
|
||||
["", ""], # ltU
|
||||
["", ""], # leU64
|
||||
["", ""], # ltU64
|
||||
["", ""], # EqEnum
|
||||
["", ""], # LeEnum
|
||||
["", ""], # LtEnum
|
||||
["", ""], # EqCh
|
||||
["", ""], # LeCh
|
||||
["", ""], # LtCh
|
||||
["", ""], # EqB
|
||||
["", ""], # LeB
|
||||
["", ""], # LtB
|
||||
["", ""], # EqRef
|
||||
["", ""], # EqUntracedRef
|
||||
["", ""], # LePtr
|
||||
["", ""], # LtPtr
|
||||
["", ""], # Xor
|
||||
["", ""], # EqCString
|
||||
["", ""], # EqProc
|
||||
["negInt", ""], # UnaryMinusI
|
||||
["negInt64", ""], # UnaryMinusI64
|
||||
["absInt", ""], # AbsI
|
||||
["", ""], # Not
|
||||
["", ""], # UnaryPlusI
|
||||
["", ""], # BitnotI
|
||||
["", ""], # UnaryPlusF64
|
||||
["", ""], # UnaryMinusF64
|
||||
["", ""], # AbsF64
|
||||
["Ze8ToI", "Ze8ToI"], # mZe8ToI
|
||||
["Ze8ToI64", "Ze8ToI64"], # mZe8ToI64
|
||||
["Ze16ToI", "Ze16ToI"], # mZe16ToI
|
||||
["Ze16ToI64", "Ze16ToI64"], # mZe16ToI64
|
||||
["Ze32ToI64", "Ze32ToI64"], # mZe32ToI64
|
||||
["ZeIToI64", "ZeIToI64"], # mZeIToI64
|
||||
["toU8", "toU8"], # toU8
|
||||
["toU16", "toU16"], # toU16
|
||||
["toU32", "toU32"], # toU32
|
||||
["", ""], # ToFloat
|
||||
["", ""], # ToBiggestFloat
|
||||
["", ""], # ToInt
|
||||
["", ""], # ToBiggestInt
|
||||
["nimCharToStr", "nimCharToStr"],
|
||||
["nimBoolToStr", "nimBoolToStr"],
|
||||
["cstrToNimstr", "cstrToNimstr"],
|
||||
["cstrToNimstr", "cstrToNimstr"],
|
||||
["cstrToNimstr", "cstrToNimstr"],
|
||||
["cstrToNimstr", "cstrToNimstr"],
|
||||
["", ""]]
|
||||
|
||||
proc needsTemp(p: PProc; n: PNode): bool =
|
||||
# check if n contains a call to determine
|
||||
@@ -478,7 +478,7 @@ proc maybeMakeTemp(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rope] =
|
||||
else:
|
||||
(a: a, tmp: b)
|
||||
|
||||
proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
# $1 and $2 in the `frmt` string bind to lhs and rhs of the expr,
|
||||
# if $3 or $4 are present they will be substituted with temps for
|
||||
# lhs and rhs respectively
|
||||
@@ -490,8 +490,8 @@ proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
var
|
||||
a, tmp = x.rdLoc
|
||||
b, tmp2 = y.rdLoc
|
||||
if "$3" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x)
|
||||
if "$4" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x)
|
||||
when "$3" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x)
|
||||
when "$4" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x)
|
||||
|
||||
r.res = frmt % [a, b, tmp, tmp2]
|
||||
r.kind = resExpr
|
||||
@@ -520,7 +520,7 @@ proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
|
||||
r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
|
||||
r.kind = resExpr
|
||||
|
||||
proc ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
template ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
var x, y, z: TCompRes
|
||||
useMagic(p, magic)
|
||||
gen(p, n.sons[1], x)
|
||||
@@ -529,7 +529,7 @@ proc ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
r.res = frmt % [x.rdLoc, y.rdLoc, z.rdLoc]
|
||||
r.kind = resExpr
|
||||
|
||||
proc unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
template unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
# $1 binds to n[1], if $2 is present it will be substituted to a tmp of $1
|
||||
useMagic(p, magic)
|
||||
gen(p, n.sons[1], r)
|
||||
@@ -541,15 +541,108 @@ proc unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||
var
|
||||
x, y: TCompRes
|
||||
xLoc,yLoc: Rope
|
||||
let i = ord(optOverflowCheck notin p.options)
|
||||
useMagic(p, jsOps[op][i])
|
||||
useMagic(p, jsMagics[op][i])
|
||||
if sonsLen(n) > 2:
|
||||
gen(p, n.sons[1], x)
|
||||
gen(p, n.sons[2], y)
|
||||
r.res = jsOps[op][i + 2] % [x.rdLoc, y.rdLoc]
|
||||
xLoc = x.rdLoc
|
||||
yLoc = y.rdLoc
|
||||
else:
|
||||
gen(p, n.sons[1], r)
|
||||
r.res = jsOps[op][i + 2] % [r.rdLoc]
|
||||
xLoc = r.rdLoc
|
||||
|
||||
template applyFormat(frmtA, frmtB: string) =
|
||||
if i == 0:
|
||||
r.res = frmtA % [xLoc, yLoc]
|
||||
else:
|
||||
r.res = frmtB % [xLoc, yLoc]
|
||||
|
||||
case op:
|
||||
of mAddI: applyFormat("addInt($1, $2)", "($1 + $2)")
|
||||
of mSubI: applyFormat("subInt($1, $2)", "($1 - $2)")
|
||||
of mMulI: applyFormat("mulInt($1, $2)", "($1 * $2)")
|
||||
of mDivI: applyFormat("divInt($1, $2)", "Math.trunc($1 / $2)")
|
||||
of mModI: applyFormat("modInt($1, $2)", "Math.trunc($1 % $2)")
|
||||
of mSucc: applyFormat("addInt($1, $2)", "($1 + $2)")
|
||||
of mPred: applyFormat("subInt($1, $2)", "($1 - $2)")
|
||||
of mAddF64: applyFormat("($1 + $2)", "($1 + $2)")
|
||||
of mSubF64: applyFormat("($1 - $2)", "($1 - $2)")
|
||||
of mMulF64: applyFormat("($1 * $2)", "($1 * $2)")
|
||||
of mDivF64: applyFormat("($1 / $2)", "($1 / $2)")
|
||||
of mShrI: applyFormat("", "")
|
||||
of mShlI: applyFormat("($1 << $2)", "($1 << $2)")
|
||||
of mAshrI: applyFormat("($1 >> $2)", "($1 >> $2)")
|
||||
of mBitandI: applyFormat("($1 & $2)", "($1 & $2)")
|
||||
of mBitorI: applyFormat("($1 | $2)", "($1 | $2)")
|
||||
of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)")
|
||||
of mMinI: applyFormat("nimMin($1, $2)", "nimMin($1, $2)")
|
||||
of mMaxI: applyFormat("nimMax($1, $2)", "nimMax($1, $2)")
|
||||
of mMinF64: applyFormat("nimMin($1, $2)", "nimMin($1, $2)")
|
||||
of mMaxF64: applyFormat("nimMax($1, $2)", "nimMax($1, $2)")
|
||||
of mAddU: applyFormat("", "")
|
||||
of msubU: applyFormat("", "")
|
||||
of mmulU: applyFormat("", "")
|
||||
of mdivU: applyFormat("", "")
|
||||
of mmodU: applyFormat("($1 % $2)", "($1 % $2)")
|
||||
of mEqI: applyFormat("($1 == $2)", "($1 == $2)")
|
||||
of mLeI: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mLtI: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mEqF64: applyFormat("($1 == $2)", "($1 == $2)")
|
||||
of mLeF64: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mLtF64: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mleU: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mltU: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mleU64: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mltU64: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mEqEnum: applyFormat("($1 == $2)", "($1 == $2)")
|
||||
of mLeEnum: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mLtEnum: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mEqCh: applyFormat("($1 == $2)", "($1 == $2)")
|
||||
of mLeCh: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mLtCh: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mEqB: applyFormat("($1 == $2)", "($1 == $2)")
|
||||
of mLeB: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mLtB: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mEqRef: applyFormat("($1 == $2)", "($1 == $2)")
|
||||
of mEqUntracedRef: applyFormat("($1 == $2)", "($1 == $2)")
|
||||
of mLePtr: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mLtPtr: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mXor: applyFormat("($1 != $2)", "($1 != $2)")
|
||||
of mEqCString: applyFormat("($1 == $2)", "($1 == $2)")
|
||||
of mEqProc: applyFormat("($1 == $2)", "($1 == $2)")
|
||||
of mUnaryMinusI: applyFormat("negInt($1)", "-($1)")
|
||||
of mUnaryMinusI64: applyFormat("negInt64($1)", "-($1)")
|
||||
of mAbsI: applyFormat("absInt($1)", "Math.abs($1)")
|
||||
of mNot: applyFormat("!($1)", "!($1)")
|
||||
of mUnaryPlusI: applyFormat("+($1)", "+($1)")
|
||||
of mBitnotI: applyFormat("~($1)", "~($1)")
|
||||
of mUnaryPlusF64: applyFormat("+($1)", "+($1)")
|
||||
of mUnaryMinusF64: applyFormat("-($1)", "-($1)")
|
||||
of mAbsF64: applyFormat("Math.abs($1)", "Math.abs($1)")
|
||||
of mZe8ToI: applyFormat("Ze8ToI($1)", "Ze8ToI($1)")
|
||||
of mZe8ToI64: applyFormat("Ze8ToI64($1)", "Ze8ToI64($1)")
|
||||
of mZe16ToI: applyFormat("Ze16ToI($1)", "Ze16ToI($1)")
|
||||
of mZe16ToI64: applyFormat("Ze16ToI64($1)", "Ze16ToI64($1)")
|
||||
of mZe32ToI64: applyFormat("Ze32ToI64($1)", "Ze32ToI64($1)")
|
||||
of mZeIToI64: applyFormat("ZeIToI64($1)", "ZeIToI64($1)")
|
||||
of mtoU8: applyFormat("toU8($1)", "toU8($1)")
|
||||
of mtoU16: applyFormat("toU16($1)", "toU16($1)")
|
||||
of mtoU32: applyFormat("toU32($1)", "toU32($1)")
|
||||
of mToFloat: applyFormat("$1", "$1")
|
||||
of mToBiggestFloat: applyFormat("$1", "$1")
|
||||
of mToInt: applyFormat("Math.trunc($1)", "Math.trunc($1)")
|
||||
of mToBiggestInt: applyFormat("Math.trunc($1)", "Math.trunc($1)")
|
||||
of mCharToStr: applyFormat("nimCharToStr($1)", "nimCharToStr($1)")
|
||||
of mBoolToStr: applyFormat("nimBoolToStr($1)", "nimBoolToStr($1)")
|
||||
of mIntToStr: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")")
|
||||
of mInt64ToStr: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")")
|
||||
of mFloatToStr: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")")
|
||||
of mCStrToStr: applyFormat("cstrToNimstr($1)", "cstrToNimstr($1)")
|
||||
of mStrToStr, mUnown: applyFormat("$1", "$1")
|
||||
else:
|
||||
assert false, $op
|
||||
|
||||
proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||
case op
|
||||
@@ -1268,6 +1361,9 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
|
||||
r.res = s.loc.r
|
||||
of skProc, skFunc, skConverter, skMethod:
|
||||
if sfCompileTime in s.flags:
|
||||
localError(p.config, n.info, "request to generate code for .compileTime proc: " &
|
||||
s.name.s)
|
||||
discard mangleName(p.module, s)
|
||||
r.res = s.loc.r
|
||||
if lfNoDecl in s.loc.flags or s.magic != mNone or
|
||||
@@ -1603,6 +1699,9 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||
else:
|
||||
varCode = "var $2"
|
||||
else:
|
||||
# Is this really a thought through feature? this basically unused
|
||||
# feature makes it impossible for almost all format strings in
|
||||
# this function to be checked at compile time.
|
||||
varCode = v.constraint.strVal
|
||||
|
||||
if n.kind == nkEmpty:
|
||||
@@ -1611,8 +1710,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||
lineF(p, "var $1 = null;$n", [varName])
|
||||
lineF(p, "var $1_Idx = 0;$n", [varName])
|
||||
else:
|
||||
lineF(p, varCode & " = $3;$n",
|
||||
[returnType, varName, createVar(p, v.typ, isIndirect(v))])
|
||||
line(p, runtimeFormat(varCode & " = $3;$n", [returnType, varName, createVar(p, v.typ, isIndirect(v))]))
|
||||
else:
|
||||
gen(p, n, a)
|
||||
case mapType(p, v.typ)
|
||||
@@ -1626,29 +1724,29 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||
let targetBaseIndex = {sfAddrTaken, sfGlobal} * v.flags == {}
|
||||
if a.typ == etyBaseIndex:
|
||||
if targetBaseIndex:
|
||||
lineF(p, varCode & " = $3, $2_Idx = $4;$n",
|
||||
[returnType, v.loc.r, a.address, a.res])
|
||||
line(p, runtimeFormat(varCode & " = $3, $2_Idx = $4;$n",
|
||||
[returnType, v.loc.r, a.address, a.res]))
|
||||
else:
|
||||
if isIndirect(v):
|
||||
lineF(p, varCode & " = [[$3, $4]];$n",
|
||||
[returnType, v.loc.r, a.address, a.res])
|
||||
line(p, runtimeFormat(varCode & " = [[$3, $4]];$n",
|
||||
[returnType, v.loc.r, a.address, a.res]))
|
||||
else:
|
||||
lineF(p, varCode & " = [$3, $4];$n",
|
||||
[returnType, v.loc.r, a.address, a.res])
|
||||
line(p, runtimeFormat(varCode & " = [$3, $4];$n",
|
||||
[returnType, v.loc.r, a.address, a.res]))
|
||||
else:
|
||||
if targetBaseIndex:
|
||||
let tmp = p.getTemp
|
||||
lineF(p, "var $1 = $2, $3 = $1[0], $3_Idx = $1[1];$n",
|
||||
[tmp, a.res, v.loc.r])
|
||||
else:
|
||||
lineF(p, varCode & " = $3;$n", [returnType, v.loc.r, a.res])
|
||||
line(p, runtimeFormat(varCode & " = $3;$n", [returnType, v.loc.r, a.res]))
|
||||
return
|
||||
else:
|
||||
s = a.res
|
||||
if isIndirect(v):
|
||||
lineF(p, varCode & " = [$3];$n", [returnType, v.loc.r, s])
|
||||
line(p, runtimeFormat(varCode & " = [$3];$n", [returnType, v.loc.r, s]))
|
||||
else:
|
||||
lineF(p, varCode & " = $3;$n", [returnType, v.loc.r, s])
|
||||
line(p, runtimeFormat(varCode & " = $3;$n", [returnType, v.loc.r, s]))
|
||||
|
||||
if useReloadingGuard:
|
||||
dec p.extraIndent
|
||||
@@ -2117,7 +2215,7 @@ proc genReturnStmt(p: PProc, n: PNode) =
|
||||
lineF(p, "break BeforeRet;$n", [])
|
||||
|
||||
proc frameCreate(p: PProc; procname, filename: Rope): Rope =
|
||||
let frameFmt =
|
||||
const frameFmt =
|
||||
"var F={procname:$1,prev:framePtr,filename:$2,line:0};$n"
|
||||
|
||||
result = p.indentLine(frameFmt % [procname, filename])
|
||||
@@ -2185,7 +2283,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
|
||||
var def: Rope
|
||||
if not prc.constraint.isNil:
|
||||
def = (prc.constraint.strVal & " {$n$#$#$#$#$#") %
|
||||
def = runtimeFormat(prc.constraint.strVal & " {$n$#$#$#$#$#",
|
||||
[ returnType,
|
||||
name,
|
||||
header,
|
||||
@@ -2193,7 +2291,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
optionalLine(p.locals),
|
||||
optionalLine(resultAsgn),
|
||||
optionalLine(genProcBody(p, prc)),
|
||||
optionalLine(p.indentLine(returnStmt))]
|
||||
optionalLine(p.indentLine(returnStmt))])
|
||||
else:
|
||||
result = ~"\L"
|
||||
|
||||
|
||||
@@ -261,7 +261,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
|
||||
proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode =
|
||||
let envParam = getHiddenParam(g, owner)
|
||||
let obj = envParam.typ.lastSon
|
||||
let obj = envParam.typ.skipTypes({tyOwned, tyRef})
|
||||
addField(obj, s, g.cache)
|
||||
|
||||
var access = newSymNode(envParam)
|
||||
@@ -320,15 +320,23 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
|
||||
rawAddSon(result, obj)
|
||||
c.ownerToType[owner.id] = result
|
||||
|
||||
proc asOwnedRef(c: DetectionPass; t: PType): PType =
|
||||
if optNimV2 in c.graph.config.globalOptions:
|
||||
assert t.kind == tyRef
|
||||
result = newType(tyOwned, t.owner)
|
||||
result.rawAddSon t
|
||||
else:
|
||||
result = t
|
||||
|
||||
proc getEnvTypeForOwnerUp(c: var DetectionPass; owner: PSym;
|
||||
info: TLineInfo): PType =
|
||||
var r = c.getEnvTypeForOwner(owner, info)
|
||||
result = newType(tyPtr, owner)
|
||||
rawAddSon(result, r.base)
|
||||
rawAddSon(result, r.skipTypes({tyOwned, tyRef}))
|
||||
|
||||
proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
|
||||
let refObj = c.getEnvTypeForOwner(dest, info) # getHiddenParam(dest).typ
|
||||
let obj = refObj.lastSon
|
||||
let obj = refObj.skipTypes({tyOwned, tyRef})
|
||||
# The assumption here is that gcDestructors means we cannot deal
|
||||
# with cycles properly, so it's better to produce a weak ref (=ptr) here.
|
||||
# This seems to be generally correct but since it's a bit risky it's only
|
||||
@@ -343,7 +351,7 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
|
||||
let upIdent = getIdent(c.graph.cache, upName)
|
||||
let upField = lookupInRecord(obj.n, upIdent)
|
||||
if upField != nil:
|
||||
if upField.typ.base != fieldType.base:
|
||||
if upField.typ.skipTypes({tyOwned, tyRef}) != fieldType.skipTypes({tyOwned, tyRef}):
|
||||
localError(c.graph.config, dep.info, "internal error: up references do not agree")
|
||||
else:
|
||||
let result = newSym(skField, upIdent, obj.owner, obj.owner.info)
|
||||
@@ -414,8 +422,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
addClosureParam(c, owner, n.info)
|
||||
if interestingIterVar(s):
|
||||
if not c.capturedVars.containsOrIncl(s.id):
|
||||
let obj = getHiddenParam(c.graph, owner).typ.lastSon
|
||||
#let obj = c.getEnvTypeForOwner(s.owner).lastSon
|
||||
let obj = getHiddenParam(c.graph, owner).typ.skipTypes({tyOwned, tyRef})
|
||||
#let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef})
|
||||
|
||||
if s.name.id == getIdent(c.graph.cache, ":state").id:
|
||||
obj.n[0].sym.id = -s.id
|
||||
@@ -440,8 +448,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
#echo "capturing ", n.info
|
||||
# variable 's' is actually captured:
|
||||
if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id):
|
||||
let obj = c.getEnvTypeForOwner(ow, n.info).lastSon
|
||||
#getHiddenParam(owner).typ.lastSon
|
||||
let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef})
|
||||
#getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef})
|
||||
addField(obj, s, c.graph.cache)
|
||||
# create required upFields:
|
||||
var w = owner.skipGenericOwner
|
||||
@@ -530,14 +538,14 @@ proc setupEnvVar(owner: PSym; d: DetectionPass;
|
||||
let envVarType = d.ownerToType.getOrDefault(owner.id)
|
||||
if envVarType.isNil:
|
||||
localError d.graph.config, owner.info, "internal error: could not determine closure type"
|
||||
result = newEnvVar(d.graph.cache, owner, envVarType)
|
||||
result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType))
|
||||
c.envVars[owner.id] = result
|
||||
|
||||
proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode =
|
||||
let p = getHiddenParam(g, owner)
|
||||
result = p.newSymNode
|
||||
if owner.isIterator:
|
||||
let upField = lookupInRecord(p.typ.lastSon.n, getIdent(g.cache, upName))
|
||||
let upField = lookupInRecord(p.typ.skipTypes({tyOwned, tyRef}).n, getIdent(g.cache, upName))
|
||||
if upField == nil:
|
||||
localError(g.config, owner.info, "could not find up reference for closure iter")
|
||||
else:
|
||||
@@ -566,10 +574,10 @@ proc rawClosureCreation(owner: PSym;
|
||||
# add ``env.param = param``
|
||||
result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
|
||||
|
||||
let upField = lookupInRecord(env.typ.lastSon.n, getIdent(d.graph.cache, upName))
|
||||
let upField = lookupInRecord(env.typ.skipTypes({tyOwned, tyRef}).n, getIdent(d.graph.cache, upName))
|
||||
if upField != nil:
|
||||
let up = getUpViaParam(d.graph, owner)
|
||||
if up != nil and upField.typ.base == up.typ.base:
|
||||
if up != nil and upField.typ.skipTypes({tyOwned, tyRef}) == up.typ.skipTypes({tyOwned, tyRef}):
|
||||
result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
|
||||
up, env.info))
|
||||
#elif oldenv != nil and oldenv.typ == upField.typ:
|
||||
@@ -584,11 +592,11 @@ proc closureCreationForIter(iter: PNode;
|
||||
let owner = iter.sym.skipGenericOwner
|
||||
var v = newSym(skVar, getIdent(d.graph.cache, envName), owner, iter.info)
|
||||
incl(v.flags, sfShadowed)
|
||||
v.typ = getHiddenParam(d.graph, iter.sym).typ
|
||||
v.typ = asOwnedRef(d, getHiddenParam(d.graph, iter.sym).typ)
|
||||
var vnode: PNode
|
||||
if owner.isIterator:
|
||||
let it = getHiddenParam(d.graph, owner)
|
||||
addUniqueField(it.typ.sons[0], v, d.graph.cache)
|
||||
addUniqueField(it.typ.skipTypes({tyOwned, tyRef}), v, d.graph.cache)
|
||||
vnode = indirectAccess(newSymNode(it), v, v.info)
|
||||
else:
|
||||
vnode = v.newSymNode
|
||||
@@ -597,10 +605,10 @@ proc closureCreationForIter(iter: PNode;
|
||||
result.add(vs)
|
||||
result.add(newCall(getSysSym(d.graph, iter.info, "internalNew"), vnode))
|
||||
|
||||
let upField = lookupInRecord(v.typ.lastSon.n, getIdent(d.graph.cache, upName))
|
||||
let upField = lookupInRecord(v.typ.skipTypes({tyOwned, tyRef}).n, getIdent(d.graph.cache, upName))
|
||||
if upField != nil:
|
||||
let u = setupEnvVar(owner, d, c)
|
||||
if u.typ.base == upField.typ.base:
|
||||
if u.typ.skipTypes({tyOwned, tyRef}) == upField.typ.skipTypes({tyOwned, tyRef}):
|
||||
result.add(newAsgnStmt(rawIndirectAccess(vnode, upField, iter.info),
|
||||
u, iter.info))
|
||||
else:
|
||||
@@ -610,7 +618,7 @@ proc closureCreationForIter(iter: PNode;
|
||||
proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode =
|
||||
let access = setupEnvVar(owner, d, c)
|
||||
let obj = access.typ.sons[0]
|
||||
let obj = access.typ.skipTypes({tyOwned, tyRef})
|
||||
let field = getFieldFromObj(obj, n.sym)
|
||||
if field != nil:
|
||||
result = rawIndirectAccess(access, field, n.info)
|
||||
@@ -619,7 +627,7 @@ proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
|
||||
result = n
|
||||
|
||||
proc getStateField*(g: ModuleGraph; owner: PSym): PSym =
|
||||
getHiddenParam(g, owner).typ.sons[0].n.sons[0].sym
|
||||
getHiddenParam(g, owner).typ.skipTypes({tyOwned, tyRef}).n.sons[0].sym
|
||||
|
||||
proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode
|
||||
@@ -644,7 +652,7 @@ proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
|
||||
while true:
|
||||
if access.typ == wanted:
|
||||
return makeClosure(d.graph, s, access, n.info)
|
||||
let obj = access.typ.sons[0]
|
||||
let obj = access.typ.skipTypes({tyOwned, tyRef})
|
||||
let upField = lookupInRecord(obj.n, getIdent(d.graph.cache, upName))
|
||||
if upField == nil:
|
||||
localError(d.graph.config, n.info, "internal error: no environment found")
|
||||
|
||||
@@ -126,7 +126,7 @@ proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
|
||||
|
||||
proc useNoGc(c: TLiftCtx; t: PType): bool {.inline.} =
|
||||
result = optNimV2 in c.graph.config.globalOptions and
|
||||
(tfHasGCedMem in t.flags or t.isGCedMem)
|
||||
({tfHasGCedMem, tfHasOwned} * t.flags != {} or t.isGCedMem)
|
||||
|
||||
proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
field: var PSym): bool =
|
||||
@@ -171,7 +171,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
body.add newAsgnCall(c.graph, op, x, y)
|
||||
result = true
|
||||
|
||||
proc addDestructorCall(c: var TLiftCtx; t: PType; body, x: PNode): bool =
|
||||
proc addDestructorCall(c: var TLiftCtx; t: PType; body, x: PNode) =
|
||||
var op = t.destructor
|
||||
if op == nil and useNoGc(c, t):
|
||||
op = produceSym(c.c, t, attachedDestructor, c.info)
|
||||
@@ -182,7 +182,6 @@ proc addDestructorCall(c: var TLiftCtx; t: PType; body, x: PNode): bool =
|
||||
markUsed(c.graph.config, c.info, op, c.graph.usageSym)
|
||||
onUse(c.info, op)
|
||||
body.add destructorCall(c.graph, op, x)
|
||||
result = true
|
||||
elif useNoGc(c, t):
|
||||
internalError(c.graph.config, c.info,
|
||||
"type-bound operator could not be resolved")
|
||||
@@ -197,7 +196,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
assert t.typeInst != nil
|
||||
# patch generic destructor:
|
||||
op = c.c.instTypeBoundOp(c.c, op, t.typeInst, c.info, attachedAsgn, 1)
|
||||
t.destructor = op
|
||||
t.attachedOps[attachedDestructor] = op
|
||||
|
||||
markUsed(c.graph.config, c.info, op, c.graph.usageSym)
|
||||
onUse(c.info, op)
|
||||
@@ -207,9 +206,9 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
of attachedAsgn:
|
||||
result = considerAsgnOrSink(c, t, body, x, y, t.assignment)
|
||||
of attachedSink:
|
||||
result = considerAsgnOrSink(c, t, body, x, y, t.sink)
|
||||
result = considerAsgnOrSink(c, t, body, x, y, t.asink)
|
||||
of attachedDeepCopy:
|
||||
let op = t.deepCopy
|
||||
let op = t.attachedOps[attachedDeepCopy]
|
||||
if op != nil:
|
||||
markUsed(c.graph.config, c.info, op, c.graph.usageSym)
|
||||
onUse(c.info, op)
|
||||
@@ -323,8 +322,8 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.add moveCall
|
||||
# alternatively we could do this:
|
||||
when false:
|
||||
doAssert t.sink != nil
|
||||
body.add newAsgnCall(c.graph, t.sink, x, y)
|
||||
doAssert t.asink != nil
|
||||
body.add newAsgnCall(c.graph, t.asink, x, y)
|
||||
of attachedDestructor:
|
||||
doAssert t.destructor != nil
|
||||
body.add destructorCall(c.graph, t.destructor, x)
|
||||
@@ -365,10 +364,10 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
#var disposeCall = genBuiltin(c.graph, mDispose, "dispose", x)
|
||||
|
||||
if isFinal(elemType):
|
||||
discard addDestructorCall(c, elemType, actions, genDeref(x))
|
||||
addDestructorCall(c, elemType, actions, genDeref(x))
|
||||
actions.add callCodegenProc(c.graph, "nimRawDispose", c.info, x)
|
||||
else:
|
||||
discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x))
|
||||
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x))
|
||||
actions.add callCodegenProc(c.graph, "nimDestroyAndDispose", c.info, x)
|
||||
|
||||
case c.kind
|
||||
@@ -502,27 +501,10 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
proc produceSymDistinctType(c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym =
|
||||
assert typ.kind == tyDistinct
|
||||
let baseType = typ[0]
|
||||
case kind
|
||||
of attachedAsgn:
|
||||
if baseType.assignment == nil:
|
||||
discard produceSym(c, baseType, kind, info)
|
||||
typ.assignment = baseType.assignment
|
||||
result = typ.assignment
|
||||
of attachedSink:
|
||||
if baseType.sink == nil:
|
||||
discard produceSym(c, baseType, kind, info)
|
||||
typ.sink = baseType.sink
|
||||
result = typ.sink
|
||||
of attachedDeepCopy:
|
||||
if baseType.deepCopy == nil:
|
||||
discard produceSym(c, baseType, kind, info)
|
||||
typ.deepCopy = baseType.deepCopy
|
||||
result = typ.deepCopy
|
||||
of attachedDestructor:
|
||||
if baseType.destructor == nil:
|
||||
discard produceSym(c, baseType, kind, info)
|
||||
typ.destructor = baseType.destructor
|
||||
result = typ.destructor
|
||||
if baseType.attachedOps[kind] == nil:
|
||||
discard produceSym(c, baseType, kind, info)
|
||||
typ.attachedOps[kind] = baseType.attachedOps[kind]
|
||||
result = typ.attachedOps[kind]
|
||||
|
||||
proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
info: TLineInfo): PSym =
|
||||
@@ -536,11 +518,7 @@ proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
a.c = c
|
||||
let g = c.graph
|
||||
let body = newNodeI(nkStmtList, info)
|
||||
let procname = case kind
|
||||
of attachedAsgn: getIdent(g.cache, "=")
|
||||
of attachedSink: getIdent(g.cache, "=sink")
|
||||
of attachedDeepCopy: getIdent(g.cache, "=deepcopy")
|
||||
of attachedDestructor: getIdent(g.cache, "=destroy")
|
||||
let procname = getIdent(g.cache, AttachedOpToStr[kind])
|
||||
|
||||
result = newSym(skProc, procname, typ.owner, info)
|
||||
a.fn = result
|
||||
@@ -557,11 +535,7 @@ proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
result.typ.addParam src
|
||||
|
||||
# register this operation already:
|
||||
case kind
|
||||
of attachedAsgn: typ.assignment = result
|
||||
of attachedSink: typ.sink = result
|
||||
of attachedDeepCopy: typ.deepCopy = result
|
||||
of attachedDestructor: typ.destructor = result
|
||||
typ.attachedOps[kind] = result
|
||||
|
||||
var tk: TTypeKind
|
||||
if optNimV2 in c.graph.config.globalOptions:
|
||||
@@ -636,23 +610,15 @@ proc createTypeBoundOps(c: PContext; orig: PType; info: TLineInfo) =
|
||||
# 5. We have a (custom) generic destructor.
|
||||
let typ = canon.skipTypes({tyGenericInst, tyAlias})
|
||||
# we generate the destructor first so that other operators can depend on it:
|
||||
if typ.destructor == nil:
|
||||
discard produceSym(c, typ, attachedDestructor, info)
|
||||
else:
|
||||
inst(typ.destructor, typ)
|
||||
if typ.assignment == nil:
|
||||
discard produceSym(c, typ, attachedAsgn, info)
|
||||
else:
|
||||
inst(typ.assignment, typ)
|
||||
if typ.sink == nil:
|
||||
discard produceSym(c, typ, attachedSink, info)
|
||||
else:
|
||||
inst(typ.sink, typ)
|
||||
for k in attachedDestructor..attachedSink:
|
||||
if typ.attachedOps[k] == nil:
|
||||
discard produceSym(c, typ, k, info)
|
||||
else:
|
||||
inst(typ.attachedOps[k], typ)
|
||||
|
||||
if overwrite:
|
||||
orig.destructor = typ.destructor
|
||||
orig.assignment = typ.assignment
|
||||
orig.sink = typ.sink
|
||||
for k in attachedDestructor..attachedSink:
|
||||
orig.attachedOps[k] = typ.attachedOps[k]
|
||||
|
||||
if not isTrival(orig.destructor):
|
||||
#or not isTrival(orig.assignment) or
|
||||
|
||||
@@ -17,9 +17,9 @@ import
|
||||
proc resetSystemArtifacts*(g: ModuleGraph) =
|
||||
magicsys.resetSysTypes(g)
|
||||
|
||||
proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: string) =
|
||||
proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) =
|
||||
let
|
||||
pck = getPackageName(graph.config, filename)
|
||||
pck = getPackageName(graph.config, filename.string)
|
||||
pck2 = if pck.len > 0: pck else: "unknown"
|
||||
pack = getIdent(graph.cache, pck2)
|
||||
var packSym = graph.packageSyms.strTableGet(pack)
|
||||
@@ -27,6 +27,22 @@ proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; fil
|
||||
packSym = newSym(skPackage, getIdent(graph.cache, pck2), nil, result.info)
|
||||
initStrTable(packSym.tab)
|
||||
graph.packageSyms.strTableAdd(packSym)
|
||||
else:
|
||||
let existing = strTableGet(packSym.tab, result.name)
|
||||
if existing != nil and existing.info.fileIndex != result.info.fileIndex:
|
||||
when false:
|
||||
# we used to produce an error:
|
||||
localError(graph.config, result.info,
|
||||
"module names need to be unique per Nimble package; module clashes with " &
|
||||
toFullPath(graph.config, existing.info.fileIndex))
|
||||
else:
|
||||
# but starting with version 0.20 we now produce a fake Nimble package instead
|
||||
# to resolve the conflicts:
|
||||
let pck3 = fakePackageName(graph.config, filename)
|
||||
packSym = newSym(skPackage, getIdent(graph.cache, pck3), nil, result.info)
|
||||
initStrTable(packSym.tab)
|
||||
graph.packageSyms.strTableAdd(packSym)
|
||||
|
||||
result.owner = packSym
|
||||
result.position = int fileIdx
|
||||
|
||||
@@ -37,13 +53,7 @@ proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; fil
|
||||
incl(result.flags, sfUsed)
|
||||
initStrTable(result.tab)
|
||||
strTableAdd(result.tab, result) # a module knows itself
|
||||
let existing = strTableGet(packSym.tab, result.name)
|
||||
if existing != nil and existing.info.fileIndex != result.info.fileIndex:
|
||||
localError(graph.config, result.info,
|
||||
"module names need to be unique per Nimble package; module clashes with " &
|
||||
toFullPath(graph.config, existing.info.fileIndex))
|
||||
# strTableIncl() for error corrections:
|
||||
discard strTableIncl(packSym.tab, result)
|
||||
strTableAdd(packSym.tab, result)
|
||||
|
||||
proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
# We cannot call ``newSym`` here, because we have to circumvent the ID
|
||||
@@ -51,7 +61,7 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
new(result)
|
||||
result.id = -1 # for better error checking
|
||||
result.kind = skModule
|
||||
let filename = toFullPath(graph.config, fileIdx)
|
||||
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
|
||||
result.name = getIdent(graph.cache, splitFile(filename).name)
|
||||
if not isNimIdentifier(result.name.s):
|
||||
rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s)
|
||||
@@ -61,8 +71,8 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): PSym =
|
||||
result = graph.getModule(fileIdx)
|
||||
if result == nil:
|
||||
let filename = toFullPath(graph.config, fileIdx)
|
||||
let (r, id) = loadModuleSym(graph, fileIdx, AbsoluteFile filename)
|
||||
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
|
||||
let (r, id) = loadModuleSym(graph, fileIdx, filename)
|
||||
result = r
|
||||
if result == nil:
|
||||
result = newModule(graph, fileIdx)
|
||||
|
||||
@@ -29,9 +29,6 @@ proc getPackageName*(conf: ConfigRef; path: string): string =
|
||||
for file in walkFiles(d / "*.nimble"):
|
||||
result = file.splitFile.name
|
||||
break packageSearch
|
||||
for file in walkFiles(d / "*.babel"):
|
||||
result = file.splitFile.name
|
||||
break packageSearch
|
||||
# we also store if we didn't find anything:
|
||||
when not defined(nimNoNilSeqs):
|
||||
if result.isNil: result = ""
|
||||
@@ -41,10 +38,19 @@ proc getPackageName*(conf: ConfigRef; path: string): string =
|
||||
dec parents
|
||||
if parents <= 0: break
|
||||
|
||||
proc fakePackageName*(conf: ConfigRef; path: AbsoluteFile): string =
|
||||
# foo/../bar becomes foo7_7bar
|
||||
result = relativeTo(path, conf.projectPath, '/').string.multiReplace(
|
||||
{"/": "7", "..": "_", "7": "77", "_": "__"})
|
||||
|
||||
proc withPackageName*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile =
|
||||
let x = getPackageName(conf, path.string)
|
||||
if x.len == 0:
|
||||
result = path
|
||||
else:
|
||||
let (p, file, ext) = path.splitFile
|
||||
result = p / RelativeFile((x & '_' & file) & ext)
|
||||
if x == "stdlib":
|
||||
# Hot code reloading now relies on 'stdlib_system' names etc.
|
||||
result = p / RelativeFile((x & '_' & file) & ext)
|
||||
else:
|
||||
result = p / RelativeFile(fakePackageName(conf, path))
|
||||
|
||||
@@ -211,7 +211,7 @@ proc ropeConcat*(a: varargs[Rope]): Rope =
|
||||
proc prepend*(a: var Rope, b: Rope) = a = b & a
|
||||
proc prepend*(a: var Rope, b: string) = a = b & a
|
||||
|
||||
proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope =
|
||||
proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
|
||||
var i = 0
|
||||
var length = len(frmt)
|
||||
result = nil
|
||||
@@ -269,7 +269,10 @@ proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope =
|
||||
add(result, substr(frmt, start, i - 1))
|
||||
assert(ropeInvariant(result))
|
||||
|
||||
proc addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
|
||||
proc `%`*(frmt: static[FormatStr], args: openArray[Rope]): Rope =
|
||||
runtimeFormat(frmt, args)
|
||||
|
||||
template addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
|
||||
## shortcut for ``add(c, frmt % args)``.
|
||||
add(c, frmt % args)
|
||||
|
||||
|
||||
@@ -72,12 +72,6 @@ type
|
||||
|
||||
TExprFlags* = set[TExprFlag]
|
||||
|
||||
TTypeAttachedOp* = enum
|
||||
attachedAsgn,
|
||||
attachedSink,
|
||||
attachedDeepCopy,
|
||||
attachedDestructor
|
||||
|
||||
PContext* = ref TContext
|
||||
TContext* = object of TPassContext # a context represents a module
|
||||
enforceVoidContext*: PType
|
||||
|
||||
@@ -937,7 +937,7 @@ proc semExprNoType(c: PContext, n: PNode): PNode =
|
||||
let isPush = hintExtendedContext in c.config.notes
|
||||
if isPush: pushInfoContext(c.config, n.info)
|
||||
result = semExpr(c, n, {efWantStmt})
|
||||
result = discardCheck(c, result, {})
|
||||
discardCheck(c, result, {})
|
||||
if isPush: popInfoContext(c.config)
|
||||
|
||||
proc isTypeExpr(n: PNode): bool =
|
||||
@@ -1526,17 +1526,52 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
|
||||
x.typ.flags.incl tfVarIsPtr
|
||||
#echo x.info, " setting it for this type ", typeToString(x.typ), " ", n.info
|
||||
|
||||
proc asgnToResult(c: PContext, n, le, ri: PNode) =
|
||||
proc borrowCheck(c: PContext, n, le, ri: PNode) =
|
||||
const
|
||||
PathKinds0 = {nkDotExpr, nkCheckedFieldExpr,
|
||||
nkBracketExpr, nkAddr, nkHiddenAddr,
|
||||
nkObjDownConv, nkObjUpConv}
|
||||
PathKinds1 = {nkHiddenStdConv, nkHiddenSubConv}
|
||||
|
||||
proc getRoot(n: PNode; followDeref: bool): PNode =
|
||||
result = n
|
||||
while true:
|
||||
case result.kind
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
if followDeref: result = result[0]
|
||||
else: break
|
||||
of PathKinds0:
|
||||
result = result[0]
|
||||
of PathKinds1:
|
||||
result = result[1]
|
||||
else: break
|
||||
|
||||
proc scopedLifetime(c: PContext; ri: PNode): bool {.inline.} =
|
||||
let n = getRoot(ri, followDeref = false)
|
||||
result = (ri.kind in nkCallKinds+{nkObjConstr}) or
|
||||
(n.kind == nkSym and n.sym.owner == c.p.owner)
|
||||
|
||||
proc escapes(c: PContext; le: PNode): bool {.inline.} =
|
||||
# param[].foo[] = self definitely escapes, we don't need to
|
||||
# care about pointer derefs:
|
||||
let n = getRoot(le, followDeref = true)
|
||||
result = n.kind == nkSym and n.sym.kind == skParam
|
||||
|
||||
# Special typing rule: do not allow to pass 'owned T' to 'T' in 'result = x':
|
||||
if ri.typ != nil and ri.typ.skipTypes(abstractInst).kind == tyOwned and
|
||||
le.typ != nil and le.typ.skipTypes(abstractInst).kind != tyOwned and ri.kind in nkCallKinds:
|
||||
localError(c.config, n.info, "cannot return an owned pointer as an unowned pointer; " &
|
||||
"use 'owned(" & typeToString(le.typ) & ")' as the return type")
|
||||
const absInst = abstractInst - {tyOwned}
|
||||
if ri.typ != nil and ri.typ.skipTypes(absInst).kind == tyOwned and
|
||||
le.typ != nil and le.typ.skipTypes(absInst).kind != tyOwned and
|
||||
scopedLifetime(c, ri):
|
||||
if le.kind == nkSym and le.sym.kind == skResult:
|
||||
localError(c.config, n.info, "cannot return an owned pointer as an unowned pointer; " &
|
||||
"use 'owned(" & typeToString(le.typ) & ")' as the return type")
|
||||
elif escapes(c, le):
|
||||
localError(c.config, n.info,
|
||||
"assignment produces a dangling ref: the unowned ref lives longer than the owned ref")
|
||||
|
||||
template resultTypeIsInferrable(typ: PType): untyped =
|
||||
typ.isMetaType and typ.kind != tyTypeDesc
|
||||
|
||||
|
||||
proc goodLineInfo(arg: PNode): TLineinfo =
|
||||
if arg.kind == nkStmtListExpr and arg.len > 0:
|
||||
goodLineInfo(arg[^1])
|
||||
@@ -1623,7 +1658,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||
c.p.owner.typ.sons[0] = rhsTyp
|
||||
else:
|
||||
typeMismatch(c.config, n.info, lhs.typ, rhsTyp)
|
||||
asgnToResult(c, n, n.sons[0], rhs)
|
||||
borrowCheck(c, n, lhs, rhs)
|
||||
|
||||
n.sons[1] = fitNode(c, le, rhs, goodLineInfo(n[1]))
|
||||
liftTypeBoundOps(c, lhs.typ, lhs.info)
|
||||
@@ -1673,7 +1708,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
|
||||
a.sons[1] = result
|
||||
result = semAsgn(c, a)
|
||||
else:
|
||||
result = discardCheck(c, result, {})
|
||||
discardCheck(c, result, {})
|
||||
|
||||
if c.p.owner.kind notin {skMacro, skTemplate} and
|
||||
c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
|
||||
|
||||
@@ -322,6 +322,39 @@ proc semOf(c: PContext, n: PNode): PNode =
|
||||
n.typ = getSysType(c.graph, n.info, tyBool)
|
||||
result = n
|
||||
|
||||
proc semUnown(c: PContext; n: PNode): PNode =
|
||||
proc unownedType(c: PContext; t: PType): PType =
|
||||
case t.kind
|
||||
of tyTuple:
|
||||
var elems = newSeq[PType](t.len)
|
||||
var someChange = false
|
||||
for i in 0..<t.len:
|
||||
elems[i] = unownedType(c, t[i])
|
||||
if elems[i] != t[i]: someChange = true
|
||||
if someChange:
|
||||
result = newType(tyTuple, t.owner)
|
||||
# we have to use 'rawAddSon' here so that type flags are
|
||||
# properly computed:
|
||||
for e in elems: result.rawAddSon(e)
|
||||
else:
|
||||
result = t
|
||||
of tyOwned: result = t.sons[0]
|
||||
of tySequence, tyOpenArray, tyArray, tyVarargs, tyVar, tyLent,
|
||||
tyGenericInst, tyAlias:
|
||||
let L = t.len-1
|
||||
let b = unownedType(c, t[L])
|
||||
if b != t[L]:
|
||||
result = copyType(t, t.owner, keepId = false)
|
||||
result[L] = b
|
||||
result.flags.excl tfHasOwned
|
||||
else:
|
||||
result = t
|
||||
else:
|
||||
result = t
|
||||
|
||||
result = copyTree(n[1])
|
||||
result.typ = unownedType(c, result.typ)
|
||||
|
||||
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
flags: TExprFlags): PNode =
|
||||
## This is the preferred code point to implement magics.
|
||||
@@ -433,4 +466,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
let t = n[1].typ.skipTypes(abstractVar)
|
||||
if t.destructor != nil:
|
||||
result.sons[0] = newSymNode(t.destructor)
|
||||
of mUnown:
|
||||
result = semUnown(c, n)
|
||||
else: result = n
|
||||
|
||||
@@ -527,7 +527,7 @@ proc isNoEffectList(n: PNode): bool {.inline.} =
|
||||
n.len == 0 or (n[tagEffects] == nil and n[exceptionEffects] == nil)
|
||||
|
||||
proc isTrival(caller: PNode): bool {.inline.} =
|
||||
result = caller.kind == nkSym and caller.sym.magic in {mEqProc, mIsNil}
|
||||
result = caller.kind == nkSym and caller.sym.magic in {mEqProc, mIsNil, mMove, mWasMoved}
|
||||
|
||||
proc trackOperand(tracked: PEffects, n: PNode, paramType: PType; caller: PNode) =
|
||||
let a = skipConvAndClosure(n)
|
||||
@@ -738,7 +738,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
mergeTags(tracked, effectList.sons[tagEffects], n)
|
||||
gcsafeAndSideeffectCheck()
|
||||
if a.kind != nkSym or a.sym.magic != mNBindSym:
|
||||
for i in 1 ..< len(n): trackOperand(tracked, n.sons[i], paramType(op, i), a)
|
||||
for i in 1 ..< n.len: trackOperand(tracked, n.sons[i], paramType(op, i), a)
|
||||
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
||||
# may not look like an assignment, but it is:
|
||||
let arg = n.sons[1]
|
||||
@@ -754,7 +754,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
track(tracked, n.sons[i])
|
||||
of nkDotExpr:
|
||||
guardDotAccess(tracked, n)
|
||||
for i in 0 ..< len(n): track(tracked, n.sons[i])
|
||||
for i in 0 ..< n.len: track(tracked, n.sons[i])
|
||||
of nkCheckedFieldExpr:
|
||||
track(tracked, n.sons[0])
|
||||
if warnProveField in tracked.config.notes:
|
||||
@@ -821,7 +821,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
of nkForStmt, nkParForStmt:
|
||||
# we are very conservative here and assume the loop is never executed:
|
||||
let oldState = tracked.init.len
|
||||
for i in 0 .. len(n)-3:
|
||||
for i in 0 .. n.len-3:
|
||||
let it = n[i]
|
||||
track(tracked, it)
|
||||
if tracked.owner.kind != skMacro:
|
||||
@@ -830,13 +830,19 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
createTypeBoundOps(tracked.c, x.typ, x.info)
|
||||
else:
|
||||
createTypeBoundOps(tracked.c, it.typ, it.info)
|
||||
for i in len(n)-2..len(n)-1:
|
||||
track(tracked, n.sons[i])
|
||||
let iterCall = n[n.len-2]
|
||||
let loopBody = n[n.len-1]
|
||||
if tracked.owner.kind != skMacro and iterCall.safelen > 1:
|
||||
# XXX this is a bit hacky:
|
||||
if iterCall[1].typ != nil and iterCall[1].typ.skipTypes(abstractVar).kind notin {tyVarargs, tyOpenArray}:
|
||||
createTypeBoundOps(tracked.c, iterCall[1].typ, iterCall[1].info)
|
||||
track(tracked, iterCall)
|
||||
track(tracked, loopBody)
|
||||
setLen(tracked.init, oldState)
|
||||
of nkObjConstr:
|
||||
when false: track(tracked, n.sons[0])
|
||||
let oldFacts = tracked.guards.s.len
|
||||
for i in 1 ..< len(n):
|
||||
for i in 1 ..< n.len:
|
||||
let x = n.sons[i]
|
||||
track(tracked, x)
|
||||
if x.sons[0].kind == nkSym and sfDiscriminant in x.sons[0].sym.flags:
|
||||
|
||||
@@ -43,7 +43,7 @@ proc semDiscard(c: PContext, n: PNode): PNode =
|
||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||
let sonType = n.sons[0].typ
|
||||
let sonKind = n.sons[0].kind
|
||||
if isEmptyType(sonType) or sonType.kind == tyNone or n.sons[0].kind == nkTypeOfExpr:
|
||||
if isEmptyType(sonType) or sonType.kind in {tyNone, tyTypeDesc} or sonKind == nkTypeOfExpr:
|
||||
localError(c.config, n.info, errInvalidDiscard)
|
||||
if sonType.kind == tyProc and sonKind notin nkCallKinds:
|
||||
# tyProc is disallowed to prevent ``discard foo`` to be valid, when ``discard foo()`` is meant.
|
||||
@@ -130,13 +130,13 @@ proc fixNilType(c: PContext; n: PNode) =
|
||||
for it in n: fixNilType(c, it)
|
||||
n.typ = nil
|
||||
|
||||
proc discardCheck(c: PContext, expr: PNode, flags: TExprFlags): PNode =
|
||||
result = expr
|
||||
proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
|
||||
if c.matchedConcept != nil or efInTypeof in flags: return
|
||||
|
||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
||||
if implicitlyDiscardable(result):
|
||||
result = newNode(nkDiscardStmt, result.info, @[result])
|
||||
var n = newNodeI(nkDiscardStmt, result.info, 1)
|
||||
n[0] = result
|
||||
elif result.typ.kind != tyError and c.config.cmd != cmdInteractive:
|
||||
var n = result
|
||||
while n.kind in skipForDiscardable: n = n.lastSon
|
||||
@@ -168,8 +168,7 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
else: illFormedAst(it, c.config)
|
||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
|
||||
(not hasElse and efInTypeof notin flags):
|
||||
for it in n:
|
||||
it.sons[^1] = discardCheck(c, it.sons[^1], flags)
|
||||
for it in n: discardCheck(c, it.lastSon, flags)
|
||||
result.kind = nkIfStmt
|
||||
# propagate any enforced VoidContext:
|
||||
if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext
|
||||
@@ -267,14 +266,12 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
|
||||
dec c.p.inTryStmt
|
||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr}:
|
||||
n.sons[0] = discardCheck(c, n.sons[0], flags)
|
||||
for i in 1..n.len-1:
|
||||
n.sons[i].sons[^1] = discardCheck(c, n.sons[i].sons[^1], flags)
|
||||
discardCheck(c, n.sons[0], flags)
|
||||
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
|
||||
if typ == c.enforceVoidContext:
|
||||
result.typ = c.enforceVoidContext
|
||||
else:
|
||||
if n.lastSon.kind == nkFinally:
|
||||
n.sons[^1].sons[^1] = discardCheck(c, n.sons[^1].sons[^1], flags)
|
||||
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon, flags)
|
||||
n.sons[0] = fitNode(c, typ, n.sons[0], n.sons[0].info)
|
||||
for i in 1..last:
|
||||
var it = n.sons[i]
|
||||
@@ -474,10 +471,14 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
($typ.kind).substr(2).toLowerAscii)
|
||||
elif typ.kind == tyProc and tfUnresolved in typ.flags:
|
||||
localError(c.config, def.info, errProcHasNoConcreteType % def.renderTree)
|
||||
elif symkind == skVar and typ.kind == tyOwned and def.kind notin nkCallKinds:
|
||||
# special type inference rule: 'var it = ownedPointer' is turned
|
||||
# into an unowned pointer.
|
||||
typ = typ.lastSon
|
||||
when false:
|
||||
# XXX This typing rule is neither documented nor complete enough to
|
||||
# justify it. Instead use the newer 'unowned x' until we figured out
|
||||
# a more general solution.
|
||||
if symkind == skVar and typ.kind == tyOwned and def.kind notin nkCallKinds:
|
||||
# special type inference rule: 'var it = ownedPointer' is turned
|
||||
# into an unowned pointer.
|
||||
typ = typ.lastSon
|
||||
else:
|
||||
if symkind == skLet: localError(c.config, a.info, errLetNeedsInit)
|
||||
|
||||
@@ -729,7 +730,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
openScope(c)
|
||||
n.sons[length-1] = semExprBranch(c, n.sons[length-1], flags)
|
||||
if efInTypeof notin flags:
|
||||
n.sons[^1] = discardCheck(c, n.sons[^1], flags)
|
||||
discardCheck(c, n.sons[length-1], flags)
|
||||
closeScope(c)
|
||||
dec(c.p.nestedLoopCounter)
|
||||
|
||||
@@ -919,8 +920,7 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
closeScope(c)
|
||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
|
||||
(not hasElse and efInTypeof notin flags):
|
||||
for i in 1..n.len-1:
|
||||
n.sons[i].sons[^1] = discardCheck(c, n.sons[i].sons[^1], flags)
|
||||
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
|
||||
# propagate any enforced VoidContext:
|
||||
if typ == c.enforceVoidContext:
|
||||
result.typ = c.enforceVoidContext
|
||||
@@ -1568,7 +1568,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
|
||||
obj = canonType(c, obj)
|
||||
if obj.destructor.isNil:
|
||||
obj.destructor = s
|
||||
obj.attachedOps[attachedDestructor] = s
|
||||
else:
|
||||
prevDestructor(c, obj.destructor, obj, n.info)
|
||||
noError = true
|
||||
@@ -1592,7 +1592,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
elif t.kind == tyGenericInvocation: t = t.sons[0]
|
||||
else: break
|
||||
if t.kind in {tyObject, tyDistinct, tyEnum, tySequence, tyString}:
|
||||
if t.deepCopy.isNil: t.deepCopy = s
|
||||
if t.attachedOps[attachedDeepCopy].isNil: t.attachedOps[attachedDeepCopy] = s
|
||||
else:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"cannot bind another 'deepCopy' to: " & typeToString(t))
|
||||
@@ -1631,11 +1631,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
# attach these ops to the canonical tySequence
|
||||
obj = canonType(c, obj)
|
||||
#echo "ATTACHING TO ", obj.id, " ", s.name.s, " ", cast[int](obj)
|
||||
let opr = if s.name.s == "=": addr(obj.assignment) else: addr(obj.sink)
|
||||
if opr[].isNil:
|
||||
opr[] = s
|
||||
let k = if name == "=": attachedAsgn else: attachedSink
|
||||
if obj.attachedOps[k].isNil:
|
||||
obj.attachedOps[k] = s
|
||||
else:
|
||||
prevDestructor(c, opr[], obj, n.info)
|
||||
prevDestructor(c, obj.attachedOps[k], obj, n.info)
|
||||
if obj.owner.getModule != s.getModule:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"type bound operation `" & name & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
|
||||
@@ -1828,7 +1828,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
|
||||
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
|
||||
if s.name.s[0] in {'.', '('}:
|
||||
if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}:
|
||||
if s.name.s in [".", ".()", ".="] and {Feature.destructor, dotOperators} * c.features == {}:
|
||||
localError(c.config, n.info, "the overloaded " & s.name.s &
|
||||
" operator has to be enabled with {.experimental: \"dotOperators\".}")
|
||||
elif s.name.s == "()" and callOperator notin c.features:
|
||||
@@ -2124,7 +2124,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
n.typ = n.sons[i].typ
|
||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||
elif i != last or voidContext:
|
||||
n.sons[i] = discardCheck(c, n.sons[i], flags)
|
||||
discardCheck(c, n.sons[i], flags)
|
||||
else:
|
||||
n.typ = n.sons[i].typ
|
||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||
|
||||
@@ -559,9 +559,11 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
s = semIdentVis(c, skTemplate, n.sons[0], {})
|
||||
|
||||
if s.owner != nil and sfSystemModule in s.owner.flags and
|
||||
s.name.s in ["!=", ">=", ">", "incl", "excl", "in", "notin", "isnot"]:
|
||||
incl(s.flags, sfCallsite)
|
||||
if s.owner != nil:
|
||||
const names = ["!=", ">=", ">", "incl", "excl", "in", "notin", "isnot"]
|
||||
if sfSystemModule in s.owner.flags and s.name.s in names or
|
||||
s.owner.name.s == "vm" and s.name.s == "stackTrace":
|
||||
incl(s.flags, sfCallsite)
|
||||
|
||||
styleCheckDef(c.config, s)
|
||||
onDef(n[0].info, s)
|
||||
|
||||
@@ -1348,8 +1348,8 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||
# special check for generic object with
|
||||
# generic/partial specialized parent
|
||||
let tx = result.skipTypes(abstractPtrs, 50)
|
||||
if tx.isNil:
|
||||
localError(c.config, n.info, "invalid recursion in type '$1'" % typeToString(result[0]))
|
||||
if tx.isNil or isTupleRecursive(tx):
|
||||
localError(c.config, n.info, "illegal recursion in type '$1'" % typeToString(result[0]))
|
||||
return errorType(c)
|
||||
if tx != result and tx.kind == tyObject and tx.sons[0] != nil:
|
||||
semObjectTypeForInheritedGenericInst(c, n, tx)
|
||||
|
||||
@@ -380,13 +380,13 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
|
||||
rawAddSon(result, newbody)
|
||||
checkPartialConstructedType(cl.c.config, cl.info, newbody)
|
||||
let dc = newbody.deepCopy
|
||||
let dc = newbody.attachedOps[attachedDeepCopy]
|
||||
if not cl.allowMetaTypes:
|
||||
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
|
||||
if dc != nil and sfFromGeneric notin newbody.attachedOps[attachedDeepCopy].flags:
|
||||
# 'deepCopy' needs to be instantiated for
|
||||
# generics *when the type is constructed*:
|
||||
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
|
||||
attachedDeepCopy, 1)
|
||||
newbody.attachedOps[attachedDeepCopy] = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
|
||||
attachedDeepCopy, 1)
|
||||
if bodyIsNew and newbody.typeInst == nil:
|
||||
#doassert newbody.typeInst == nil
|
||||
newbody.typeInst = result
|
||||
@@ -592,7 +592,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
skipIntLiteralParams(result)
|
||||
|
||||
of tySequence:
|
||||
if cl.isReturnType and cl.c.config.selectedGc == gcDestructors and result.destructor.isNil and
|
||||
if cl.isReturnType and cl.c.config.selectedGc == gcDestructors and
|
||||
result.attachedOps[attachedDestructor].isNil and
|
||||
result[0].kind != tyEmpty and optNimV2 notin cl.c.config.globalOptions:
|
||||
let s = cl.c.graph.sysTypes[tySequence]
|
||||
var old = copyType(s, s.owner, keepId=false)
|
||||
@@ -601,9 +602,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
old.n = nil
|
||||
old.flags = {tfHasAsgn}
|
||||
old.addSonSkipIntLit result[0]
|
||||
result.destructor = old.destructor
|
||||
result.assignment = old.assignment
|
||||
result.sink = old.sink
|
||||
result.attachedOps = old.attachedOps
|
||||
cl.c.typesWithOps.add((result, old))
|
||||
|
||||
else: discard
|
||||
@@ -619,19 +618,19 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
result.n = replaceObjBranches(cl, result.n)
|
||||
|
||||
template typeBound(c, newty, oldty, field, info) =
|
||||
let opr = newty.field
|
||||
let opr = newty.attachedOps[field]
|
||||
if opr != nil and sfFromGeneric notin opr.flags:
|
||||
# '=' needs to be instantiated for generics when the type is constructed:
|
||||
#echo "DESTROY: instantiating ", astToStr(field), " for ", typeToString(oldty)
|
||||
newty.field = c.instTypeBoundOp(c, opr, oldty, info, attachedAsgn, 1)
|
||||
newty.attachedOps[field] = c.instTypeBoundOp(c, opr, oldty, info, attachedAsgn, 1)
|
||||
|
||||
proc instAllTypeBoundOp*(c: PContext, info: TLineInfo) =
|
||||
var i = 0
|
||||
while i < c.typesWithOps.len:
|
||||
let (newty, oldty) = c.typesWithOps[i]
|
||||
typeBound(c, newty, oldty, destructor, info)
|
||||
typeBound(c, newty, oldty, sink, info)
|
||||
typeBound(c, newty, oldty, assignment, info)
|
||||
typeBound(c, newty, oldty, attachedDestructor, info)
|
||||
typeBound(c, newty, oldty, attachedSink, info)
|
||||
typeBound(c, newty, oldty, attachedAsgn, info)
|
||||
inc i
|
||||
setLen(c.typesWithOps, 0)
|
||||
|
||||
|
||||
@@ -349,7 +349,7 @@ proc hashBodyTree(graph: ModuleGraph, c: var MD5Context, n: PNode) =
|
||||
c &= n.strVal
|
||||
else:
|
||||
for i in 0..<n.len:
|
||||
hashTree(c, n.sons[i])
|
||||
hashBodyTree(graph, c, n.sons[i])
|
||||
|
||||
proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash =
|
||||
## compute unique digest of the proc/func/method symbols
|
||||
@@ -369,7 +369,7 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash =
|
||||
if sym.ast != nil:
|
||||
md5Init(c)
|
||||
c.md5Update(cast[cstring](result.addr), sizeof(result))
|
||||
c.hashTree(sym.ast[bodyPos])
|
||||
hashBodyTree(graph, c, sym.ast[bodyPos])
|
||||
c.md5Final(result.Md5Digest)
|
||||
graph.symBodyHashes[sym.id] = result
|
||||
|
||||
|
||||
@@ -2092,14 +2092,21 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||
result = localConvMatch(c, m, f, a, arg)
|
||||
else:
|
||||
r = typeRel(m, base(f), a)
|
||||
if r >= isGeneric:
|
||||
case r
|
||||
of isGeneric:
|
||||
inc(m.convMatches)
|
||||
result = copyTree(arg)
|
||||
if r == isGeneric:
|
||||
result.typ = getInstantiatedType(c, arg, m, base(f))
|
||||
result.typ = getInstantiatedType(c, arg, m, base(f))
|
||||
m.baseTypeMatch = true
|
||||
# bug #4799, varargs accepting subtype relation object
|
||||
elif r == isSubtype:
|
||||
of isFromIntLit:
|
||||
inc(m.intConvMatches, 256)
|
||||
result = implicitConv(nkHiddenStdConv, f[0], arg, m, c)
|
||||
m.baseTypeMatch = true
|
||||
of isEqual:
|
||||
inc(m.convMatches)
|
||||
result = copyTree(arg)
|
||||
m.baseTypeMatch = true
|
||||
of isSubtype: # bug #4799, varargs accepting subtype relation object
|
||||
inc(m.subtypeMatches)
|
||||
if base(f).kind == tyTypeDesc:
|
||||
result = arg
|
||||
|
||||
@@ -651,6 +651,8 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||
var t = formal.typ
|
||||
if formal.ast != nil and formal.ast.typ.destructor != nil and t.destructor == nil:
|
||||
t = formal.ast.typ # better use the type that actually has a destructor.
|
||||
elif t.destructor == nil and arg.typ.destructor != nil:
|
||||
t = arg.typ
|
||||
# generate a temporary and produce an assignment statement:
|
||||
var temp = newTemp(c, t, formal.info)
|
||||
#temp.sym.flags.incl sfCursor
|
||||
|
||||
@@ -101,7 +101,7 @@ proc isDeepConstExpr*(n: PNode): bool =
|
||||
if not isDeepConstExpr(n.sons[i]): return false
|
||||
if n.typ.isNil: result = true
|
||||
else:
|
||||
let t = n.typ.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink})
|
||||
let t = n.typ.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink, tyOwned})
|
||||
if t.kind in {tyRef, tyPtr}: return false
|
||||
if t.kind != tyObject or not isCaseObj(t.n):
|
||||
result = true
|
||||
|
||||
@@ -931,6 +931,21 @@ proc ldNullOpcode(t: PType): TOpcode =
|
||||
assert t != nil
|
||||
if fitsRegister(t): opcLdNullReg else: opcLdNull
|
||||
|
||||
proc whichAsgnOpc(n: PNode): TOpcode =
|
||||
case n.typ.skipTypes(abstractRange+{tyOwned}-{tyTypeDesc}).kind
|
||||
of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
opcAsgnInt
|
||||
of tyString, tyCString:
|
||||
opcAsgnStr
|
||||
of tyFloat..tyFloat128:
|
||||
opcAsgnFloat
|
||||
of tyRef, tyNil, tyVar, tyLent, tyPtr:
|
||||
opcAsgnRef
|
||||
else:
|
||||
opcAsgnComplex
|
||||
|
||||
proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode = opc
|
||||
|
||||
proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
case m
|
||||
of mAnd: c.genAndOr(n, opcFJmp, dest)
|
||||
@@ -957,7 +972,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
c.genNarrow(n.sons[1], d)
|
||||
c.genAsgnPatch(n.sons[1], d)
|
||||
c.freeTemp(d)
|
||||
of mOrd, mChr, mArrToSeq: c.gen(n.sons[1], dest)
|
||||
of mOrd, mChr, mArrToSeq, mUnown: c.gen(n.sons[1], dest)
|
||||
of mNew, mNewFinalize:
|
||||
unused(c, n, dest)
|
||||
c.genNew(n)
|
||||
@@ -1330,6 +1345,17 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
of mRunnableExamples:
|
||||
discard "just ignore any call to runnableExamples"
|
||||
of mDestroy: discard "ignore calls to the default destructor"
|
||||
of mMove:
|
||||
let arg = n[1]
|
||||
let a = c.genx(arg)
|
||||
assert dest >= 0
|
||||
if dest < 0: dest = c.getTemp(arg.typ)
|
||||
gABC(c, arg, whichAsgnOpc(arg), dest, a, 1)
|
||||
# XXX use ldNullOpcode() here?
|
||||
c.gABx(n, opcLdNull, a, c.genType(arg.typ))
|
||||
c.gABx(n, opcNodeToReg, a, a)
|
||||
c.genAsgnPatch(arg, a)
|
||||
c.freeTemp(a)
|
||||
else:
|
||||
# mGCref, mGCunref,
|
||||
globalError(c.config, n.info, "cannot generate code for: " & $m)
|
||||
@@ -1423,21 +1449,6 @@ proc genDeref(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
|
||||
if {gfNodeAddr, gfNode} * flags == {} and fitsRegister(n.typ):
|
||||
c.gABC(n, opcNodeToReg, dest, dest)
|
||||
|
||||
proc whichAsgnOpc(n: PNode): TOpcode =
|
||||
case n.typ.skipTypes(abstractRange+{tyOwned}-{tyTypeDesc}).kind
|
||||
of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
opcAsgnInt
|
||||
of tyString, tyCString:
|
||||
opcAsgnStr
|
||||
of tyFloat..tyFloat128:
|
||||
opcAsgnFloat
|
||||
of tyRef, tyNil, tyVar, tyLent, tyPtr:
|
||||
opcAsgnRef
|
||||
else:
|
||||
opcAsgnComplex
|
||||
|
||||
proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode = opc
|
||||
|
||||
proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
|
||||
let tmp = c.genx(ri)
|
||||
assert dest >= 0
|
||||
@@ -1585,8 +1596,8 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
|
||||
# var decls{.compileTime.}: seq[NimNode] = @[]
|
||||
let dest = c.getTemp(s.typ)
|
||||
c.gABx(n, opcLdGlobal, dest, s.position)
|
||||
if s.ast != nil:
|
||||
let tmp = c.genx(s.ast)
|
||||
if s.astdef != nil:
|
||||
let tmp = c.genx(s.astdef)
|
||||
c.genAdditionalCopy(n, opcWrDeref, dest, 0, tmp)
|
||||
c.freeTemp(dest)
|
||||
c.freeTemp(tmp)
|
||||
|
||||
Reference in New Issue
Block a user