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

@ -419,7 +419,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
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 & ')')

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
------------------ ------------------