disallow negative indexing

This commit is contained in:
Araq 2015-03-26 17:27:51 +01:00
commit ed0d9e271d
7 changed files with 164 additions and 148 deletions

View file

@ -557,6 +557,7 @@ type
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mSlice, mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mSlice,
mDotDot, # this one is only necessary to give nice compile time warnings
mFields, mFieldPairs, mOmpParFor, mFields, mFieldPairs, mOmpParFor,
mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,

View file

@ -1749,6 +1749,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, x, a) initLocExpr(p, x, a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
genDeepCopy(p, a, b) genDeepCopy(p, a, b)
of mDotDot: genCall(p, e, d)
else: internalError(e.info, "genMagicExpr: " & $op) else: internalError(e.info, "genMagicExpr: " & $op)
proc genConstExpr(p: BProc, n: PNode): PRope proc genConstExpr(p: BProc, n: PNode): PRope

View file

@ -10,8 +10,8 @@
# this module folds constants; used by semantic checking phase # this module folds constants; used by semantic checking phase
# and evaluation phase # and evaluation phase
import import
strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times, strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times,
nversion, platform, math, msgs, os, condsyms, idents, renderer, types, nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
commands, magicsys, saturate commands, magicsys, saturate
@ -41,7 +41,7 @@ proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
result.typ = n.typ result.typ = n.typ
result.info = n.info result.info = n.info
proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode = proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode =
result = newFloatNode(nkFloatLit, floatVal) result = newFloatNode(nkFloatLit, floatVal)
if skipTypes(n.typ, abstractVarRange).kind == tyFloat: if skipTypes(n.typ, abstractVarRange).kind == tyFloat:
result.typ = getFloatLitType(result) result.typ = getFloatLitType(result)
@ -49,27 +49,27 @@ proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode =
result.typ = n.typ result.typ = n.typ
result.info = n.info result.info = n.info
proc newStrNodeT(strVal: string, n: PNode): PNode = proc newStrNodeT(strVal: string, n: PNode): PNode =
result = newStrNode(nkStrLit, strVal) result = newStrNode(nkStrLit, strVal)
result.typ = n.typ result.typ = n.typ
result.info = n.info result.info = n.info
proc ordinalValToString*(a: PNode): string = proc ordinalValToString*(a: PNode): string =
# because $ has the param ordinal[T], `a` is not necessarily an enum, but an # because $ has the param ordinal[T], `a` is not necessarily an enum, but an
# ordinal # ordinal
var x = getInt(a) var x = getInt(a)
var t = skipTypes(a.typ, abstractRange) var t = skipTypes(a.typ, abstractRange)
case t.kind case t.kind
of tyChar: of tyChar:
result = $chr(int(x) and 0xff) result = $chr(int(x) and 0xff)
of tyEnum: of tyEnum:
var n = t.n var n = t.n
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind != nkSym: internalError(a.info, "ordinalValToString") if n.sons[i].kind != nkSym: internalError(a.info, "ordinalValToString")
var field = n.sons[i].sym var field = n.sons[i].sym
if field.position == x: if field.position == x:
if field.ast == nil: if field.ast == nil:
return field.name.s return field.name.s
else: else:
return field.ast.strVal return field.ast.strVal
@ -112,7 +112,7 @@ proc pickMaxInt(n: PNode): BiggestInt =
else: else:
internalError(n.info, "pickMaxInt") internalError(n.info, "pickMaxInt")
proc makeRange(typ: PType, first, last: BiggestInt): PType = proc makeRange(typ: PType, first, last: BiggestInt): PType =
let minA = min(first, last) let minA = min(first, last)
let maxA = max(first, last) let maxA = max(first, last)
let lowerNode = newIntNode(nkIntLit, minA) let lowerNode = newIntNode(nkIntLit, minA)
@ -138,7 +138,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
# Nimrod requires interval arithmetic for ``range`` types. Lots of tedious # Nimrod requires interval arithmetic for ``range`` types. Lots of tedious
# work but the feature is very nice for reducing explicit conversions. # work but the feature is very nice for reducing explicit conversions.
result = n.typ result = n.typ
template commutativeOp(opr: expr) {.immediate.} = template commutativeOp(opr: expr) {.immediate.} =
let a = n.sons[1] let a = n.sons[1]
let b = n.sons[2] let b = n.sons[2]
@ -146,7 +146,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
result = makeRange(pickIntRange(a.typ, b.typ), result = makeRange(pickIntRange(a.typ, b.typ),
opr(pickMinInt(a), pickMinInt(b)), opr(pickMinInt(a), pickMinInt(b)),
opr(pickMaxInt(a), pickMaxInt(b))) opr(pickMaxInt(a), pickMaxInt(b)))
template binaryOp(opr: expr) {.immediate.} = template binaryOp(opr: expr) {.immediate.} =
let a = n.sons[1] let a = n.sons[1]
let b = n.sons[2] let b = n.sons[2]
@ -154,7 +154,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
result = makeRange(a.typ, result = makeRange(a.typ,
opr(pickMinInt(a), pickMinInt(b)), opr(pickMinInt(a), pickMinInt(b)),
opr(pickMaxInt(a), pickMaxInt(b))) opr(pickMaxInt(a), pickMaxInt(b)))
case m case m
of mUnaryMinusI, mUnaryMinusI64: of mUnaryMinusI, mUnaryMinusI64:
let a = n.sons[1].typ let a = n.sons[1].typ
@ -231,7 +231,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
of mMaxI, mMaxI64: of mMaxI, mMaxI64:
commutativeOp(max) commutativeOp(max)
else: discard else: discard
discard """ discard """
mShlI, mShlI64, mShlI, mShlI64,
mShrI, mShrI64, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64 mShrI, mShrI64, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64
@ -242,7 +242,7 @@ proc evalIs(n, a: PNode): PNode =
internalAssert a.kind == nkSym and a.sym.kind == skType internalAssert a.kind == nkSym and a.sym.kind == skType
internalAssert n.sonsLen == 3 and internalAssert n.sonsLen == 3 and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType} n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
let t1 = a.sym.typ let t1 = a.sym.typ
if n[2].kind in {nkStrLit..nkTripleStrLit}: if n[2].kind in {nkStrLit..nkTripleStrLit}:
@ -250,12 +250,12 @@ proc evalIs(n, a: PNode): PNode =
of "closure": of "closure":
let t = skipTypes(t1, abstractRange) let t = skipTypes(t1, abstractRange)
result = newIntNode(nkIntLit, ord(t.kind == tyProc and result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and t.callConv == ccClosure and
tfIterator notin t.flags)) tfIterator notin t.flags))
of "iterator": of "iterator":
let t = skipTypes(t1, abstractRange) let t = skipTypes(t1, abstractRange)
result = newIntNode(nkIntLit, ord(t.kind == tyProc and result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and t.callConv == ccClosure and
tfIterator in t.flags)) tfIterator in t.flags))
else: discard else: discard
else: else:
@ -265,7 +265,7 @@ proc evalIs(n, a: PNode): PNode =
result = newIntNode(nkIntLit, ord(match)) result = newIntNode(nkIntLit, ord(match))
result.typ = n.typ result.typ = n.typ
proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
# b and c may be nil # b and c may be nil
result = nil result = nil
case m case m
@ -280,14 +280,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n) of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
of mLengthSeq, mLengthOpenArray: result = newIntNodeT(sonsLen(a), n) # BUGFIX of mLengthSeq, mLengthOpenArray: result = newIntNodeT(sonsLen(a), n) # BUGFIX
of mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: result = a # throw `+` away of mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: result = a # throw `+` away
of mToFloat, mToBiggestFloat: of mToFloat, mToBiggestFloat:
result = newFloatNodeT(toFloat(int(getInt(a))), n) result = newFloatNodeT(toFloat(int(getInt(a))), n)
of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n) of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n) of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n)
of mAbsI, mAbsI64: of mAbsI, mAbsI64:
if getInt(a) >= 0: result = a if getInt(a) >= 0: result = a
else: result = newIntNodeT(- getInt(a), n) else: result = newIntNodeT(- getInt(a), n)
of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64: of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
# byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64 # byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64
result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n) result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n)
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n) of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n)
@ -299,21 +299,21 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mAddI, mAddI64: result = newIntNodeT(getInt(a) + getInt(b), n) of mAddI, mAddI64: result = newIntNodeT(getInt(a) + getInt(b), n)
of mSubI, mSubI64: result = newIntNodeT(getInt(a) - getInt(b), n) of mSubI, mSubI64: result = newIntNodeT(getInt(a) - getInt(b), n)
of mMulI, mMulI64: result = newIntNodeT(getInt(a) * getInt(b), n) of mMulI, mMulI64: result = newIntNodeT(getInt(a) * getInt(b), n)
of mMinI, mMinI64: of mMinI, mMinI64:
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n) if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
else: result = newIntNodeT(getInt(a), n) else: result = newIntNodeT(getInt(a), n)
of mMaxI, mMaxI64: of mMaxI, mMaxI64:
if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n) if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n)
else: result = newIntNodeT(getInt(b), n) else: result = newIntNodeT(getInt(b), n)
of mShlI, mShlI64: of mShlI, mShlI64:
case skipTypes(n.typ, abstractRange).kind case skipTypes(n.typ, abstractRange).kind
of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n) of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n)
of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n) of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n)
of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n) of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n)
of tyInt64, tyInt, tyUInt..tyUInt64: of tyInt64, tyInt, tyUInt..tyUInt64:
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n) result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
else: internalError(n.info, "constant folding for shl") else: internalError(n.info, "constant folding for shl")
of mShrI, mShrI64: of mShrI, mShrI64:
case skipTypes(n.typ, abstractRange).kind case skipTypes(n.typ, abstractRange).kind
of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n) of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n)
of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n) of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n)
@ -332,34 +332,34 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n) of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n) of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n) of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
of mDivF64: of mDivF64:
if getFloat(b) == 0.0: if getFloat(b) == 0.0:
if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n) if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n)
else: result = newFloatNodeT(Inf, n) else: result = newFloatNodeT(Inf, n)
else: else:
result = newFloatNodeT(getFloat(a) / getFloat(b), n) result = newFloatNodeT(getFloat(a) / getFloat(b), n)
of mMaxF64: of mMaxF64:
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n) if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n)
else: result = newFloatNodeT(getFloat(b), n) else: result = newFloatNodeT(getFloat(b), n)
of mMinF64: of mMinF64:
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n) if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n)
else: result = newFloatNodeT(getFloat(a), n) else: result = newFloatNodeT(getFloat(a), n)
of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n) of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n)
of mLtI, mLtI64, mLtB, mLtEnum, mLtCh: of mLtI, mLtI64, mLtB, mLtEnum, mLtCh:
result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n) result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n)
of mLeI, mLeI64, mLeB, mLeEnum, mLeCh: of mLeI, mLeI64, mLeB, mLeEnum, mLeCh:
result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n) result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n)
of mEqI, mEqI64, mEqB, mEqEnum, mEqCh: of mEqI, mEqI64, mEqB, mEqEnum, mEqCh:
result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n) result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n)
of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n) of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n)
of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n) of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n)
of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n) of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n)
of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n) of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n)
of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n) of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n)
of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n) of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n)
of mLtU, mLtU64: of mLtU, mLtU64:
result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n) result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n)
of mLeU, mLeU64: of mLeU, mLeU64:
result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n) result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n)
of mBitandI, mBitandI64, mAnd: result = newIntNodeT(a.getInt and b.getInt, n) of mBitandI, mBitandI64, mAnd: result = newIntNodeT(a.getInt and b.getInt, n)
of mBitorI, mBitorI64, mOr: result = newIntNodeT(getInt(a) or getInt(b), n) of mBitorI, mBitorI64, mOr: result = newIntNodeT(getInt(a) or getInt(b), n)
@ -377,18 +377,18 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
result = newIntNodeT(`/%`(getInt(a), y), n) result = newIntNodeT(`/%`(getInt(a), y), n)
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n) of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n) of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
of mLtSet: of mLtSet:
result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n) result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n)
of mMulSet: of mMulSet:
result = nimsets.intersectSets(a, b) result = nimsets.intersectSets(a, b)
result.info = n.info result.info = n.info
of mPlusSet: of mPlusSet:
result = nimsets.unionSets(a, b) result = nimsets.unionSets(a, b)
result.info = n.info result.info = n.info
of mMinusSet: of mMinusSet:
result = nimsets.diffSets(a, b) result = nimsets.diffSets(a, b)
result.info = n.info result.info = n.info
of mSymDiffSet: of mSymDiffSet:
result = nimsets.symdiffSets(a, b) result = nimsets.symdiffSets(a, b)
result.info = n.info result.info = n.info
of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n) of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n)
@ -397,104 +397,104 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
# BUGFIX: we cannot eval mRepr here for reasons that I forgot. # BUGFIX: we cannot eval mRepr here for reasons that I forgot.
discard discard
of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n) of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n)
of mBoolToStr: of mBoolToStr:
if getOrdValue(a) == 0: result = newStrNodeT("false", n) if getOrdValue(a) == 0: result = newStrNodeT("false", n)
else: result = newStrNodeT("true", n) else: result = newStrNodeT("true", n)
of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n) of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n)
of mCopyStrLast: of mCopyStrLast:
result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)), result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)),
int(getOrdValue(c))), n) int(getOrdValue(c))), n)
of mFloatToStr: result = newStrNodeT($getFloat(a), n) of mFloatToStr: result = newStrNodeT($getFloat(a), n)
of mCStrToStr, mCharToStr: result = newStrNodeT(getStrOrChar(a), n) of mCStrToStr, mCharToStr: result = newStrNodeT(getStrOrChar(a), n)
of mStrToStr: result = a of mStrToStr: result = a
of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n) of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n)
of mArrToSeq: of mArrToSeq:
result = copyTree(a) result = copyTree(a)
result.typ = n.typ result.typ = n.typ
of mCompileOption: of mCompileOption:
result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n) result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n)
of mCompileOptionArg: of mCompileOptionArg:
result = newIntNodeT(ord( result = newIntNodeT(ord(
testCompileOptionArg(getStr(a), getStr(b), n.info)), n) testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
of mNewString, mNewStringOfCap, of mNewString, mNewStringOfCap,
mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh, mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot,
mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, mParallel: mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, mParallel:
discard discard
else: internalError(a.info, "evalOp(" & $m & ')') else: internalError(a.info, "evalOp(" & $m & ')')
proc getConstIfExpr(c: PSym, n: PNode): PNode = proc getConstIfExpr(c: PSym, n: PNode): PNode =
result = nil result = nil
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i] var it = n.sons[i]
if it.len == 2: if it.len == 2:
var e = getConstExpr(c, it.sons[0]) var e = getConstExpr(c, it.sons[0])
if e == nil: return nil if e == nil: return nil
if getOrdValue(e) != 0: if getOrdValue(e) != 0:
if result == nil: if result == nil:
result = getConstExpr(c, it.sons[1]) result = getConstExpr(c, it.sons[1])
if result == nil: return if result == nil: return
elif it.len == 1: elif it.len == 1:
if result == nil: result = getConstExpr(c, it.sons[0]) if result == nil: result = getConstExpr(c, it.sons[0])
else: internalError(it.info, "getConstIfExpr()") else: internalError(it.info, "getConstIfExpr()")
proc partialAndExpr(c: PSym, n: PNode): PNode = proc partialAndExpr(c: PSym, n: PNode): PNode =
# partial evaluation # partial evaluation
result = n result = n
var a = getConstExpr(c, n.sons[1]) var a = getConstExpr(c, n.sons[1])
var b = getConstExpr(c, n.sons[2]) var b = getConstExpr(c, n.sons[2])
if a != nil: if a != nil:
if getInt(a) == 0: result = a if getInt(a) == 0: result = a
elif b != nil: result = b elif b != nil: result = b
else: result = n.sons[2] else: result = n.sons[2]
elif b != nil: elif b != nil:
if getInt(b) == 0: result = b if getInt(b) == 0: result = b
else: result = n.sons[1] else: result = n.sons[1]
proc partialOrExpr(c: PSym, n: PNode): PNode = proc partialOrExpr(c: PSym, n: PNode): PNode =
# partial evaluation # partial evaluation
result = n result = n
var a = getConstExpr(c, n.sons[1]) var a = getConstExpr(c, n.sons[1])
var b = getConstExpr(c, n.sons[2]) var b = getConstExpr(c, n.sons[2])
if a != nil: if a != nil:
if getInt(a) != 0: result = a if getInt(a) != 0: result = a
elif b != nil: result = b elif b != nil: result = b
else: result = n.sons[2] else: result = n.sons[2]
elif b != nil: elif b != nil:
if getInt(b) != 0: result = b if getInt(b) != 0: result = b
else: result = n.sons[1] else: result = n.sons[1]
proc leValueConv(a, b: PNode): bool = proc leValueConv(a, b: PNode): bool =
result = false result = false
case a.kind case a.kind
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
case b.kind case b.kind
of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal) of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal)
else: internalError(a.info, "leValueConv") else: internalError(a.info, "leValueConv")
of nkFloatLit..nkFloat128Lit: of nkFloatLit..nkFloat128Lit:
case b.kind case b.kind
of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal
of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal)) of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal))
else: internalError(a.info, "leValueConv") else: internalError(a.info, "leValueConv")
else: internalError(a.info, "leValueConv") else: internalError(a.info, "leValueConv")
proc magicCall(m: PSym, n: PNode): PNode = proc magicCall(m: PSym, n: PNode): PNode =
if sonsLen(n) <= 1: return if sonsLen(n) <= 1: return
var s = n.sons[0].sym var s = n.sons[0].sym
var a = getConstExpr(m, n.sons[1]) var a = getConstExpr(m, n.sons[1])
var b, c: PNode var b, c: PNode
if a == nil: return if a == nil: return
if sonsLen(n) > 2: if sonsLen(n) > 2:
b = getConstExpr(m, n.sons[2]) b = getConstExpr(m, n.sons[2])
if b == nil: return if b == nil: return
if sonsLen(n) > 3: if sonsLen(n) > 3:
c = getConstExpr(m, n.sons[3]) c = getConstExpr(m, n.sons[3])
if c == nil: return if c == nil: return
result = evalOp(s.magic, n, a, b, c) result = evalOp(s.magic, n, a, b, c)
proc getAppType(n: PNode): PNode = proc getAppType(n: PNode): PNode =
if gGlobalOptions.contains(optGenDynLib): if gGlobalOptions.contains(optGenDynLib):
result = newStrNodeT("lib", n) result = newStrNodeT("lib", n)
@ -510,48 +510,48 @@ proc rangeCheck(n: PNode, value: BiggestInt) =
localError(n.info, errGenerated, "cannot convert " & $value & localError(n.info, errGenerated, "cannot convert " & $value &
" to " & typeToString(n.typ)) " to " & typeToString(n.typ))
proc foldConv*(n, a: PNode; check = false): PNode = proc foldConv*(n, a: PNode; check = false): PNode =
# XXX range checks? # XXX range checks?
case skipTypes(n.typ, abstractRange).kind case skipTypes(n.typ, abstractRange).kind
of tyInt..tyInt64: of tyInt..tyInt64:
case skipTypes(a.typ, abstractRange).kind case skipTypes(a.typ, abstractRange).kind
of tyFloat..tyFloat64: of tyFloat..tyFloat64:
result = newIntNodeT(int(getFloat(a)), n) result = newIntNodeT(int(getFloat(a)), n)
of tyChar: result = newIntNodeT(getOrdValue(a), n) of tyChar: result = newIntNodeT(getOrdValue(a), n)
else: else:
result = a result = a
result.typ = n.typ result.typ = n.typ
if check: rangeCheck(n, result.intVal) if check: rangeCheck(n, result.intVal)
of tyFloat..tyFloat64: of tyFloat..tyFloat64:
case skipTypes(a.typ, abstractRange).kind case skipTypes(a.typ, abstractRange).kind
of tyInt..tyInt64, tyEnum, tyBool, tyChar: of tyInt..tyInt64, tyEnum, tyBool, tyChar:
result = newFloatNodeT(toFloat(int(getOrdValue(a))), n) result = newFloatNodeT(toFloat(int(getOrdValue(a))), n)
else: else:
result = a result = a
result.typ = n.typ result.typ = n.typ
of tyOpenArray, tyVarargs, tyProc: of tyOpenArray, tyVarargs, tyProc:
discard discard
else: else:
result = a result = a
result.typ = n.typ result.typ = n.typ
proc getArrayConstr(m: PSym, n: PNode): PNode = proc getArrayConstr(m: PSym, n: PNode): PNode =
if n.kind == nkBracket: if n.kind == nkBracket:
result = n result = n
else: else:
result = getConstExpr(m, n) result = getConstExpr(m, n)
if result == nil: result = n if result == nil: result = n
proc foldArrayAccess(m: PSym, n: PNode): PNode = proc foldArrayAccess(m: PSym, n: PNode): PNode =
var x = getConstExpr(m, n.sons[0]) var x = getConstExpr(m, n.sons[0])
if x == nil or x.typ.skipTypes({tyGenericInst}).kind == tyTypeDesc: return if x == nil or x.typ.skipTypes({tyGenericInst}).kind == tyTypeDesc: return
var y = getConstExpr(m, n.sons[1]) var y = getConstExpr(m, n.sons[1])
if y == nil: return if y == nil: return
var idx = getOrdValue(y) var idx = getOrdValue(y)
case x.kind case x.kind
of nkPar: of nkPar:
if idx >= 0 and idx < sonsLen(x): if idx >= 0 and idx < sonsLen(x):
result = x.sons[int(idx)] result = x.sons[int(idx)]
if result.kind == nkExprColonExpr: result = result.sons[1] if result.kind == nkExprColonExpr: result = result.sons[1]
@ -563,14 +563,14 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
else: localError(n.info, errIndexOutOfBounds) else: localError(n.info, errIndexOutOfBounds)
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
result = newNodeIT(nkCharLit, x.info, n.typ) result = newNodeIT(nkCharLit, x.info, n.typ)
if idx >= 0 and idx < len(x.strVal): if idx >= 0 and idx < len(x.strVal):
result.intVal = ord(x.strVal[int(idx)]) result.intVal = ord(x.strVal[int(idx)])
elif idx == len(x.strVal): elif idx == len(x.strVal):
discard discard
else: else:
localError(n.info, errIndexOutOfBounds) localError(n.info, errIndexOutOfBounds)
else: discard else: discard
proc foldFieldAccess(m: PSym, n: PNode): PNode = proc foldFieldAccess(m: PSym, n: PNode): PNode =
# a real field access; proc calls have already been transformed # a real field access; proc calls have already been transformed
var x = getConstExpr(m, n.sons[0]) var x = getConstExpr(m, n.sons[0])
@ -584,15 +584,15 @@ proc foldFieldAccess(m: PSym, n: PNode): PNode =
result = x.sons[field.position] result = x.sons[field.position]
if result.kind == nkExprColonExpr: result = result.sons[1] if result.kind == nkExprColonExpr: result = result.sons[1]
return return
if it.sons[0].sym.name.id == field.name.id: if it.sons[0].sym.name.id == field.name.id:
result = x.sons[i].sons[1] result = x.sons[i].sons[1]
return return
localError(n.info, errFieldXNotFound, field.name.s) localError(n.info, errFieldXNotFound, field.name.s)
proc foldConStrStr(m: PSym, n: PNode): PNode = proc foldConStrStr(m: PSym, n: PNode): PNode =
result = newNodeIT(nkStrLit, n.info, n.typ) result = newNodeIT(nkStrLit, n.info, n.typ)
result.strVal = "" result.strVal = ""
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
let a = getConstExpr(m, n.sons[i]) let a = getConstExpr(m, n.sons[i])
if a == nil: return nil if a == nil: return nil
result.strVal.add(getStrOrChar(a)) result.strVal.add(getStrOrChar(a))
@ -602,10 +602,10 @@ proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
result.typ = newType(tyTypeDesc, s.owner) result.typ = newType(tyTypeDesc, s.owner)
result.typ.addSonSkipIntLit(s.typ) result.typ.addSonSkipIntLit(s.typ)
proc getConstExpr(m: PSym, n: PNode): PNode = proc getConstExpr(m: PSym, n: PNode): PNode =
result = nil result = nil
case n.kind case n.kind
of nkSym: of nkSym:
var s = n.sym var s = n.sym
case s.kind case s.kind
of skEnumField: of skEnumField:
@ -636,14 +636,14 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
else: else:
result = newSymNodeTypeDesc(s, n.info) result = newSymNodeTypeDesc(s, n.info)
else: discard else: discard
of nkCharLit..nkNilLit: of nkCharLit..nkNilLit:
result = copyNode(n) result = copyNode(n)
of nkIfExpr: of nkIfExpr:
result = getConstIfExpr(m, n) result = getConstIfExpr(m, n)
of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix: of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix:
if n.sons[0].kind != nkSym: return if n.sons[0].kind != nkSym: return
var s = n.sons[0].sym var s = n.sons[0].sym
if s.kind != skProc: return if s.kind != skProc: return
try: try:
case s.magic case s.magic
of mNone: of mNone:
@ -651,8 +651,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
return return
of mSizeOf: of mSizeOf:
var a = n.sons[1] var a = n.sons[1]
if computeSize(a.typ) < 0: if computeSize(a.typ) < 0:
localError(a.info, errCannotEvalXBecauseIncompletelyDefined, localError(a.info, errCannotEvalXBecauseIncompletelyDefined,
"sizeof") "sizeof")
result = nil result = nil
elif skipTypes(a.typ, typedescInst).kind in elif skipTypes(a.typ, typedescInst).kind in
@ -662,21 +662,21 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
else: else:
result = nil result = nil
# XXX: size computation for complex types is still wrong # XXX: size computation for complex types is still wrong
of mLow: of mLow:
result = newIntNodeT(firstOrd(n.sons[1].typ), n) result = newIntNodeT(firstOrd(n.sons[1].typ), n)
of mHigh: of mHigh:
if skipTypes(n.sons[1].typ, abstractVar).kind notin if skipTypes(n.sons[1].typ, abstractVar).kind notin
{tySequence, tyString, tyCString, tyOpenArray, tyVarargs}: {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n) result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n)
else: else:
var a = getArrayConstr(m, n.sons[1]) var a = getArrayConstr(m, n.sons[1])
if a.kind == nkBracket: if a.kind == nkBracket:
# we can optimize it away: # we can optimize it away:
result = newIntNodeT(sonsLen(a)-1, n) result = newIntNodeT(sonsLen(a)-1, n)
of mLengthOpenArray: of mLengthOpenArray:
var a = getArrayConstr(m, n.sons[1]) var a = getArrayConstr(m, n.sons[1])
if a.kind == nkBracket: if a.kind == nkBracket:
# we can optimize it away! This fixes the bug ``len(134)``. # we can optimize it away! This fixes the bug ``len(134)``.
result = newIntNodeT(sonsLen(a), n) result = newIntNodeT(sonsLen(a), n)
else: else:
result = magicCall(m, n) result = magicCall(m, n)
@ -694,33 +694,33 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = evalIs(n, a) result = evalIs(n, a)
else: else:
result = magicCall(m, n) result = magicCall(m, n)
except OverflowError: except OverflowError:
localError(n.info, errOverOrUnderflow) localError(n.info, errOverOrUnderflow)
except DivByZeroError: except DivByZeroError:
localError(n.info, errConstantDivisionByZero) localError(n.info, errConstantDivisionByZero)
of nkAddr: of nkAddr:
var a = getConstExpr(m, n.sons[0]) var a = getConstExpr(m, n.sons[0])
if a != nil: if a != nil:
result = n result = n
n.sons[0] = a n.sons[0] = a
of nkBracket: of nkBracket:
result = copyTree(n) result = copyTree(n)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i]) var a = getConstExpr(m, n.sons[i])
if a == nil: return nil if a == nil: return nil
result.sons[i] = a result.sons[i] = a
incl(result.flags, nfAllConst) incl(result.flags, nfAllConst)
of nkRange: of nkRange:
var a = getConstExpr(m, n.sons[0]) var a = getConstExpr(m, n.sons[0])
if a == nil: return if a == nil: return
var b = getConstExpr(m, n.sons[1]) var b = getConstExpr(m, n.sons[1])
if b == nil: return if b == nil: return
result = copyNode(n) result = copyNode(n)
addSon(result, a) addSon(result, a)
addSon(result, b) addSon(result, b)
of nkCurly: of nkCurly:
result = copyTree(n) result = copyTree(n)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i]) var a = getConstExpr(m, n.sons[i])
if a == nil: return nil if a == nil: return nil
result.sons[i] = a result.sons[i] = a
@ -735,33 +735,33 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of nkPar: of nkPar:
# tuple constructor # tuple constructor
result = copyTree(n) result = copyTree(n)
if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr): if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr):
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i].sons[1]) var a = getConstExpr(m, n.sons[i].sons[1])
if a == nil: return nil if a == nil: return nil
result.sons[i].sons[1] = a result.sons[i].sons[1] = a
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i]) var a = getConstExpr(m, n.sons[i])
if a == nil: return nil if a == nil: return nil
result.sons[i] = a result.sons[i] = a
incl(result.flags, nfAllConst) incl(result.flags, nfAllConst)
of nkChckRangeF, nkChckRange64, nkChckRange: of nkChckRangeF, nkChckRange64, nkChckRange:
var a = getConstExpr(m, n.sons[0]) var a = getConstExpr(m, n.sons[0])
if a == nil: return if a == nil: return
if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]): if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]):
result = a # a <= x and x <= b result = a # a <= x and x <= b
result.typ = n.typ result.typ = n.typ
else: else:
localError(n.info, errGenerated, `%`( localError(n.info, errGenerated, `%`(
msgKindToString(errIllegalConvFromXtoY), msgKindToString(errIllegalConvFromXtoY),
[typeToString(n.sons[0].typ), typeToString(n.typ)])) [typeToString(n.sons[0].typ), typeToString(n.typ)]))
of nkStringToCString, nkCStringToString: of nkStringToCString, nkCStringToString:
var a = getConstExpr(m, n.sons[0]) var a = getConstExpr(m, n.sons[0])
if a == nil: return if a == nil: return
result = a result = a
result.typ = n.typ result.typ = n.typ
of nkHiddenStdConv, nkHiddenSubConv, nkConv: of nkHiddenStdConv, nkHiddenSubConv, nkConv:
var a = getConstExpr(m, n.sons[1]) var a = getConstExpr(m, n.sons[1])
if a == nil: return if a == nil: return
result = foldConv(n, a, check=n.kind == nkHiddenStdConv) result = foldConv(n, a, check=n.kind == nkHiddenStdConv)

View file

@ -135,6 +135,13 @@ proc isStrangeArray(t: PType): bool =
let t = t.skipTypes(abstractInst) let t = t.skipTypes(abstractInst)
result = t.kind == tyArray and t.firstOrd != 0 result = t.kind == tyArray and t.firstOrd != 0
proc isNegative(n: PNode): bool =
let n = n.skipConv
if n.kind in {nkCharLit..nkUInt64Lit}:
result = n.intVal < 0
elif n.kind in nkCallKinds and n.sons[0].kind == nkSym:
result = n.sons[0].sym.magic in {mUnaryMinusI, mUnaryMinusI64}
proc magicsAfterOverloadResolution(c: PContext, n: PNode, proc magicsAfterOverloadResolution(c: PContext, n: PNode,
flags: TExprFlags): PNode = flags: TExprFlags): PNode =
case n[0].sym.magic case n[0].sym.magic
@ -158,6 +165,12 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mProcCall: of mProcCall:
result = n result = n
result.typ = n[1].typ result.typ = n[1].typ
of mDotDot:
result = n
# we only need to warnings here about negative indexing:
if isNegative(n.sons[1]) or (n.len > 2 and isNegative(n.sons[2])):
message(n.info, warnDeprecated,
"use '^' instead of '-'; negative indexing")
of mRoof: of mRoof:
# error correction: # error correction:
result = n.sons[1] result = n.sons[1]

View file

@ -228,7 +228,7 @@ type
when defined(nimalias): when defined(nimalias):
{.deprecated: [TSlice: Slice].} {.deprecated: [TSlice: Slice].}
proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline.} = proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} =
## `slice`:idx: operator that constructs an interval ``[a, b]``, both `a` ## `slice`:idx: operator that constructs an interval ``[a, b]``, both `a`
## and `b` are inclusive. Slices can also be used in the set constructor ## and `b` are inclusive. Slices can also be used in the set constructor
## and in ordinal case statements, but then they are special-cased by the ## and in ordinal case statements, but then they are special-cased by the
@ -236,7 +236,7 @@ proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline.} =
result.a = a result.a = a
result.b = b result.b = b
proc `..`*[T](b: T): Slice[T] {.noSideEffect, inline.} = proc `..`*[T](b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} =
## `slice`:idx: operator that constructs an interval ``[default(T), b]`` ## `slice`:idx: operator that constructs an interval ``[default(T), b]``
result.b = b result.b = b
@ -2864,11 +2864,11 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} =
when hostOS != "standalone": when hostOS != "standalone":
proc `[]`*(s: string, x: Slice[int]): string {.inline.} = proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
## slice operation for strings. Negative indexes are supported. ## slice operation for strings.
result = s.substr(x.a-|s, x.b-|s) result = s.substr(x.a-|s, x.b-|s)
proc `[]=`*(s: var string, x: Slice[int], b: string) = proc `[]=`*(s: var string, x: Slice[int], b: string) =
## slice assignment for strings. Negative indexes are supported. If ## slice assignment for strings. If
## ``b.len`` is not exactly the number of elements that are referred to ## ``b.len`` is not exactly the number of elements that are referred to
## by `x`, a `splice`:idx: is performed: ## by `x`, a `splice`:idx: is performed:
## ##
@ -2884,8 +2884,7 @@ when hostOS != "standalone":
spliceImpl(s, a, L, b) spliceImpl(s, a, L, b)
proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] = proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] =
## slice operation for arrays. Negative indexes are **not** supported ## slice operation for arrays.
## because the array might have negative bounds.
when low(a) < 0: when low(a) < 0:
{.error: "Slicing for arrays with negative indices is unsupported.".} {.error: "Slicing for arrays with negative indices is unsupported.".}
var L = x.b - x.a + 1 var L = x.b - x.a + 1
@ -2893,8 +2892,7 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] =
for i in 0.. <L: result[i] = a[i + x.a] for i in 0.. <L: result[i] = a[i + x.a]
proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) = proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) =
## slice assignment for arrays. Negative indexes are **not** supported ## slice assignment for arrays.
## because the array might have negative bounds.
when low(a) < 0: when low(a) < 0:
{.error: "Slicing for arrays with negative indices is unsupported.".} {.error: "Slicing for arrays with negative indices is unsupported.".}
var L = x.b - x.a + 1 var L = x.b - x.a + 1
@ -2904,16 +2902,14 @@ proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) =
sysFatal(RangeError, "different lengths for slice assignment") sysFatal(RangeError, "different lengths for slice assignment")
proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] = proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] =
## slice operation for arrays. Negative indexes are **not** supported ## slice operation for arrays.
## because the array might have negative bounds.
var L = ord(x.b) - ord(x.a) + 1 var L = ord(x.b) - ord(x.a) + 1
newSeq(result, L) newSeq(result, L)
for i in 0.. <L: for i in 0.. <L:
result[i] = a[Idx(ord(x.a) + i)] result[i] = a[Idx(ord(x.a) + i)]
proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) = proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) =
## slice assignment for arrays. Negative indexes are **not** supported ## slice assignment for arrays.
## because the array might have negative bounds.
var L = ord(x.b) - ord(x.a) + 1 var L = ord(x.b) - ord(x.a) + 1
if L == b.len: if L == b.len:
for i in 0 .. <L: for i in 0 .. <L:
@ -2922,14 +2918,14 @@ proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) =
sysFatal(RangeError, "different lengths for slice assignment") sysFatal(RangeError, "different lengths for slice assignment")
proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] = proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] =
## slice operation for sequences. Negative indexes are supported. ## slice operation for sequences.
var a = x.a-|s var a = x.a-|s
var L = x.b-|s - a + 1 var L = x.b-|s - a + 1
newSeq(result, L) newSeq(result, L)
for i in 0.. <L: result[i] = s[i + a] for i in 0.. <L: result[i] = s[i + a]
proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) = proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) =
## slice assignment for sequences. Negative indexes are supported. If ## slice assignment for sequences. If
## ``b.len`` is not exactly the number of elements that are referred to ## ``b.len`` is not exactly the number of elements that are referred to
## by `x`, a `splice`:idx: is performed. ## by `x`, a `splice`:idx: is performed.
var a = x.a-|s var a = x.a-|s

View file

@ -6,7 +6,6 @@ version 0.10.4
- make 'nil' work for 'add' and 'len' - make 'nil' work for 'add' and 'len'
- add "all threads are blocked" detection to 'spawn' - add "all threads are blocked" detection to 'spawn'
- overloading of '=' - overloading of '='
- disallow negative indexing
version 1.0 version 1.0

View file

@ -59,6 +59,12 @@ News
echo x.T echo x.T
inc x inc x
- **Negative indexing for slicing is deprecated and will be removed in the
next version of the language.** Instead of ``a[0.. -1]`` you can
use ``a[0.. ^1]``. This also works with accessing a single
element ``a[^1]``. Note that we cannot detect this reliably as it is
determined at **runtime** whether negative indexing is used!
Language Additions Language Additions
------------------ ------------------