diff options
author | Araq <rumpf_a@web.de> | 2015-03-26 17:27:51 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2015-03-27 01:30:06 +0100 |
commit | ed0d9e271d602ddd149350422f60c497df1c61fd (patch) | |
tree | c7a45a667398d8f2bf6f56b7f392d912336b6207 | |
parent | 96d15e92587f37228213ba0e7ec6e67997e5d39c (diff) | |
download | Nim-ed0d9e271d602ddd149350422f60c497df1c61fd.tar.gz |
disallow negative indexing
-rw-r--r-- | compiler/ast.nim | 1 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 1 | ||||
-rw-r--r-- | compiler/semfold.nim | 266 | ||||
-rw-r--r-- | compiler/semmagic.nim | 13 | ||||
-rw-r--r-- | lib/system.nim | 24 | ||||
-rw-r--r-- | todo.txt | 1 | ||||
-rw-r--r-- | web/news.txt | 6 |
7 files changed, 164 insertions, 148 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index b82a3887d..10f2a71da 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -557,6 +557,7 @@ type mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mSlice, + mDotDot, # this one is only necessary to give nice compile time warnings mFields, mFieldPairs, mOmpParFor, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a280abc31..aa1bf31be 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1749,6 +1749,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = initLocExpr(p, x, a) initLocExpr(p, e.sons[2], b) genDeepCopy(p, a, b) + of mDotDot: genCall(p, e, d) else: internalError(e.info, "genMagicExpr: " & $op) proc genConstExpr(p: BProc, n: PNode): PRope diff --git a/compiler/semfold.nim b/compiler/semfold.nim index a3f1b1c13..2e7179673 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -10,8 +10,8 @@ # this module folds constants; used by semantic checking phase # and evaluation phase -import - strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times, +import + strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times, nversion, platform, math, msgs, os, condsyms, idents, renderer, types, commands, magicsys, saturate @@ -41,7 +41,7 @@ proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode = result.typ = n.typ result.info = n.info -proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode = +proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode = result = newFloatNode(nkFloatLit, floatVal) if skipTypes(n.typ, abstractVarRange).kind == tyFloat: result.typ = getFloatLitType(result) @@ -49,27 +49,27 @@ proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode = result.typ = n.typ result.info = n.info -proc newStrNodeT(strVal: string, n: PNode): PNode = +proc newStrNodeT(strVal: string, n: PNode): PNode = result = newStrNode(nkStrLit, strVal) result.typ = n.typ 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 # ordinal var x = getInt(a) - + var t = skipTypes(a.typ, abstractRange) case t.kind - of tyChar: + of tyChar: result = $chr(int(x) and 0xff) of tyEnum: 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") var field = n.sons[i].sym - if field.position == x: - if field.ast == nil: + if field.position == x: + if field.ast == nil: return field.name.s else: return field.ast.strVal @@ -112,7 +112,7 @@ proc pickMaxInt(n: PNode): BiggestInt = else: 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 maxA = max(first, last) 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 # work but the feature is very nice for reducing explicit conversions. result = n.typ - + template commutativeOp(opr: expr) {.immediate.} = let a = n.sons[1] let b = n.sons[2] @@ -146,7 +146,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType = result = makeRange(pickIntRange(a.typ, b.typ), opr(pickMinInt(a), pickMinInt(b)), opr(pickMaxInt(a), pickMaxInt(b))) - + template binaryOp(opr: expr) {.immediate.} = let a = n.sons[1] let b = n.sons[2] @@ -154,7 +154,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType = result = makeRange(a.typ, opr(pickMinInt(a), pickMinInt(b)), opr(pickMaxInt(a), pickMaxInt(b))) - + case m of mUnaryMinusI, mUnaryMinusI64: let a = n.sons[1].typ @@ -231,7 +231,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType = of mMaxI, mMaxI64: commutativeOp(max) else: discard - + discard """ mShlI, mShlI64, 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 n.sonsLen == 3 and n[2].kind in {nkStrLit..nkTripleStrLit, nkType} - + let t1 = a.sym.typ if n[2].kind in {nkStrLit..nkTripleStrLit}: @@ -250,12 +250,12 @@ proc evalIs(n, a: PNode): PNode = of "closure": let t = skipTypes(t1, abstractRange) result = newIntNode(nkIntLit, ord(t.kind == tyProc and - t.callConv == ccClosure and + t.callConv == ccClosure and tfIterator notin t.flags)) of "iterator": let t = skipTypes(t1, abstractRange) result = newIntNode(nkIntLit, ord(t.kind == tyProc and - t.callConv == ccClosure and + t.callConv == ccClosure and tfIterator in t.flags)) else: discard else: @@ -265,7 +265,7 @@ proc evalIs(n, a: PNode): PNode = result = newIntNode(nkIntLit, ord(match)) 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 result = nil 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 mLengthSeq, mLengthOpenArray: result = newIntNodeT(sonsLen(a), n) # BUGFIX of mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: result = a # throw `+` away - of mToFloat, mToBiggestFloat: + of mToFloat, mToBiggestFloat: result = newFloatNodeT(toFloat(int(getInt(a))), n) of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n) of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n) - of mAbsI, mAbsI64: + of mAbsI, mAbsI64: if getInt(a) >= 0: result = a 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 result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), 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 mSubI, mSubI64: 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) else: result = newIntNodeT(getInt(a), n) - of mMaxI, mMaxI64: + of mMaxI, mMaxI64: if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n) else: result = newIntNodeT(getInt(b), n) - of mShlI, mShlI64: + of mShlI, mShlI64: case skipTypes(n.typ, abstractRange).kind 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 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) else: internalError(n.info, "constant folding for shl") - of mShrI, mShrI64: + of mShrI, mShrI64: case skipTypes(n.typ, abstractRange).kind of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(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 mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n) of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n) - of mDivF64: - if getFloat(b) == 0.0: + of mDivF64: + if getFloat(b) == 0.0: if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n) else: result = newFloatNodeT(Inf, n) - else: + else: result = newFloatNodeT(getFloat(a) / getFloat(b), n) - of mMaxF64: + of mMaxF64: if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n) else: result = newFloatNodeT(getFloat(b), n) - of mMinF64: + of mMinF64: if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n) else: result = newFloatNodeT(getFloat(a), 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) - of mLeI, mLeI64, mLeB, mLeEnum, mLeCh: + of mLeI, mLeI64, mLeB, mLeEnum, mLeCh: result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n) - of mEqI, mEqI64, mEqB, mEqEnum, mEqCh: - result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n) + of mEqI, mEqI64, mEqB, mEqEnum, mEqCh: + result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n) of mLtF64: 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 mLeStr: 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) - of mLeU, mLeU64: + of mLeU, mLeU64: result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), 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) @@ -377,18 +377,18 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = result = newIntNodeT(`/%`(getInt(a), y), n) of mLeSet: result = newIntNodeT(ord(containsSets(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) - of mMulSet: + of mMulSet: result = nimsets.intersectSets(a, b) result.info = n.info - of mPlusSet: + of mPlusSet: result = nimsets.unionSets(a, b) result.info = n.info - of mMinusSet: + of mMinusSet: result = nimsets.diffSets(a, b) result.info = n.info - of mSymDiffSet: + of mSymDiffSet: result = nimsets.symdiffSets(a, b) result.info = n.info 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. discard of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n) - of mBoolToStr: + of mBoolToStr: if getOrdValue(a) == 0: result = newStrNodeT("false", n) else: result = newStrNodeT("true", n) of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n) - of mCopyStrLast: - result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)), + of mCopyStrLast: + result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)), int(getOrdValue(c))), n) of mFloatToStr: result = newStrNodeT($getFloat(a), n) of mCStrToStr, mCharToStr: result = newStrNodeT(getStrOrChar(a), n) of mStrToStr: result = a of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n) - of mArrToSeq: + of mArrToSeq: result = copyTree(a) result.typ = n.typ of mCompileOption: - result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n) + result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n) of mCompileOptionArg: result = newIntNodeT(ord( testCompileOptionArg(getStr(a), getStr(b), n.info)), n) - of mNewString, mNewStringOfCap, - mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh, - mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, - mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, + of mNewString, mNewStringOfCap, + mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh, + mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, + mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot, mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, mParallel: discard else: internalError(a.info, "evalOp(" & $m & ')') - -proc getConstIfExpr(c: PSym, n: PNode): PNode = + +proc getConstIfExpr(c: PSym, n: PNode): PNode = result = nil - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): var it = n.sons[i] if it.len == 2: var e = getConstExpr(c, it.sons[0]) if e == nil: return nil - if getOrdValue(e) != 0: - if result == nil: + if getOrdValue(e) != 0: + if result == nil: result = getConstExpr(c, it.sons[1]) - if result == nil: return + if result == nil: return elif it.len == 1: if result == nil: result = getConstExpr(c, it.sons[0]) else: internalError(it.info, "getConstIfExpr()") -proc partialAndExpr(c: PSym, n: PNode): PNode = +proc partialAndExpr(c: PSym, n: PNode): PNode = # partial evaluation result = n var a = getConstExpr(c, n.sons[1]) var b = getConstExpr(c, n.sons[2]) - if a != nil: + if a != nil: if getInt(a) == 0: result = a elif b != nil: result = b else: result = n.sons[2] - elif b != nil: + elif b != nil: if getInt(b) == 0: result = b else: result = n.sons[1] - -proc partialOrExpr(c: PSym, n: PNode): PNode = + +proc partialOrExpr(c: PSym, n: PNode): PNode = # partial evaluation result = n var a = getConstExpr(c, n.sons[1]) var b = getConstExpr(c, n.sons[2]) - if a != nil: + if a != nil: if getInt(a) != 0: result = a elif b != nil: result = b else: result = n.sons[2] - elif b != nil: + elif b != nil: if getInt(b) != 0: result = b else: result = n.sons[1] - -proc leValueConv(a, b: PNode): bool = + +proc leValueConv(a, b: PNode): bool = result = false case a.kind - of nkCharLit..nkUInt64Lit: + of nkCharLit..nkUInt64Lit: case b.kind of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal) else: internalError(a.info, "leValueConv") - of nkFloatLit..nkFloat128Lit: + of nkFloatLit..nkFloat128Lit: case b.kind of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal)) else: internalError(a.info, "leValueConv") else: internalError(a.info, "leValueConv") - + proc magicCall(m: PSym, n: PNode): PNode = if sonsLen(n) <= 1: return var s = n.sons[0].sym var a = getConstExpr(m, n.sons[1]) var b, c: PNode - if a == nil: return - if sonsLen(n) > 2: + if a == nil: return + if sonsLen(n) > 2: b = getConstExpr(m, n.sons[2]) - if b == nil: return - if sonsLen(n) > 3: + if b == nil: return + if sonsLen(n) > 3: c = getConstExpr(m, n.sons[3]) - if c == nil: return + if c == nil: return result = evalOp(s.magic, n, a, b, c) - + proc getAppType(n: PNode): PNode = if gGlobalOptions.contains(optGenDynLib): result = newStrNodeT("lib", n) @@ -510,48 +510,48 @@ proc rangeCheck(n: PNode, value: BiggestInt) = localError(n.info, errGenerated, "cannot convert " & $value & " to " & typeToString(n.typ)) -proc foldConv*(n, a: PNode; check = false): PNode = +proc foldConv*(n, a: PNode; check = false): PNode = # XXX range checks? case skipTypes(n.typ, abstractRange).kind - of tyInt..tyInt64: + of tyInt..tyInt64: case skipTypes(a.typ, abstractRange).kind of tyFloat..tyFloat64: result = newIntNodeT(int(getFloat(a)), n) of tyChar: result = newIntNodeT(getOrdValue(a), n) - else: + else: result = a result.typ = n.typ if check: rangeCheck(n, result.intVal) of tyFloat..tyFloat64: 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) else: result = a result.typ = n.typ - of tyOpenArray, tyVarargs, tyProc: + of tyOpenArray, tyVarargs, tyProc: discard - else: + else: result = a result.typ = n.typ - + proc getArrayConstr(m: PSym, n: PNode): PNode = if n.kind == nkBracket: result = n else: result = getConstExpr(m, 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]) if x == nil or x.typ.skipTypes({tyGenericInst}).kind == tyTypeDesc: return - + var y = getConstExpr(m, n.sons[1]) if y == nil: return - + var idx = getOrdValue(y) case x.kind - of nkPar: + of nkPar: if idx >= 0 and idx < sonsLen(x): result = x.sons[int(idx)] if result.kind == nkExprColonExpr: result = result.sons[1] @@ -563,14 +563,14 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode = else: localError(n.info, errIndexOutOfBounds) of nkStrLit..nkTripleStrLit: 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)]) - elif idx == len(x.strVal): + elif idx == len(x.strVal): discard - else: + else: localError(n.info, errIndexOutOfBounds) else: discard - + proc foldFieldAccess(m: PSym, n: PNode): PNode = # a real field access; proc calls have already been transformed var x = getConstExpr(m, n.sons[0]) @@ -584,15 +584,15 @@ proc foldFieldAccess(m: PSym, n: PNode): PNode = result = x.sons[field.position] if result.kind == nkExprColonExpr: result = result.sons[1] 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] return 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.strVal = "" - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): let a = getConstExpr(m, n.sons[i]) if a == nil: return nil result.strVal.add(getStrOrChar(a)) @@ -602,10 +602,10 @@ proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode = result.typ = newType(tyTypeDesc, s.owner) result.typ.addSonSkipIntLit(s.typ) -proc getConstExpr(m: PSym, n: PNode): PNode = +proc getConstExpr(m: PSym, n: PNode): PNode = result = nil case n.kind - of nkSym: + of nkSym: var s = n.sym case s.kind of skEnumField: @@ -636,14 +636,14 @@ proc getConstExpr(m: PSym, n: PNode): PNode = else: result = newSymNodeTypeDesc(s, n.info) else: discard - of nkCharLit..nkNilLit: + of nkCharLit..nkNilLit: result = copyNode(n) - of nkIfExpr: + of nkIfExpr: result = getConstIfExpr(m, n) - of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix: - if n.sons[0].kind != nkSym: return + of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix: + if n.sons[0].kind != nkSym: return var s = n.sons[0].sym - if s.kind != skProc: return + if s.kind != skProc: return try: case s.magic of mNone: @@ -651,8 +651,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode = return of mSizeOf: var a = n.sons[1] - if computeSize(a.typ) < 0: - localError(a.info, errCannotEvalXBecauseIncompletelyDefined, + if computeSize(a.typ) < 0: + localError(a.info, errCannotEvalXBecauseIncompletelyDefined, "sizeof") result = nil elif skipTypes(a.typ, typedescInst).kind in @@ -662,21 +662,21 @@ proc getConstExpr(m: PSym, n: PNode): PNode = else: result = nil # XXX: size computation for complex types is still wrong - of mLow: + of mLow: result = newIntNodeT(firstOrd(n.sons[1].typ), n) - of mHigh: + of mHigh: if skipTypes(n.sons[1].typ, abstractVar).kind notin {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}: result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n) else: var a = getArrayConstr(m, n.sons[1]) if a.kind == nkBracket: - # we can optimize it away: + # we can optimize it away: result = newIntNodeT(sonsLen(a)-1, n) of mLengthOpenArray: var a = getArrayConstr(m, n.sons[1]) 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) else: result = magicCall(m, n) @@ -694,33 +694,33 @@ proc getConstExpr(m: PSym, n: PNode): PNode = result = evalIs(n, a) else: result = magicCall(m, n) - except OverflowError: + except OverflowError: localError(n.info, errOverOrUnderflow) - except DivByZeroError: + except DivByZeroError: localError(n.info, errConstantDivisionByZero) - of nkAddr: + of nkAddr: var a = getConstExpr(m, n.sons[0]) - if a != nil: + if a != nil: result = n n.sons[0] = a - of nkBracket: + of nkBracket: 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]) if a == nil: return nil result.sons[i] = a incl(result.flags, nfAllConst) - of nkRange: + of nkRange: var a = getConstExpr(m, n.sons[0]) - if a == nil: return + if a == nil: return var b = getConstExpr(m, n.sons[1]) - if b == nil: return + if b == nil: return result = copyNode(n) addSon(result, a) addSon(result, b) - of nkCurly: + of nkCurly: 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]) if a == nil: return nil result.sons[i] = a @@ -735,33 +735,33 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of nkPar: # tuple constructor result = copyTree(n) - if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr): - for i in countup(0, sonsLen(n) - 1): + if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr): + for i in countup(0, sonsLen(n) - 1): var a = getConstExpr(m, n.sons[i].sons[1]) if a == nil: return nil result.sons[i].sons[1] = a - else: - for i in countup(0, sonsLen(n) - 1): + else: + for i in countup(0, sonsLen(n) - 1): var a = getConstExpr(m, n.sons[i]) if a == nil: return nil result.sons[i] = a incl(result.flags, nfAllConst) - of nkChckRangeF, nkChckRange64, nkChckRange: + of nkChckRangeF, nkChckRange64, nkChckRange: var a = getConstExpr(m, n.sons[0]) - if a == nil: return - if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]): + if a == nil: return + if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]): result = a # a <= x and x <= b result.typ = n.typ - else: + else: localError(n.info, errGenerated, `%`( - msgKindToString(errIllegalConvFromXtoY), + msgKindToString(errIllegalConvFromXtoY), [typeToString(n.sons[0].typ), typeToString(n.typ)])) - of nkStringToCString, nkCStringToString: + of nkStringToCString, nkCStringToString: var a = getConstExpr(m, n.sons[0]) - if a == nil: return + if a == nil: return result = a result.typ = n.typ - of nkHiddenStdConv, nkHiddenSubConv, nkConv: + of nkHiddenStdConv, nkHiddenSubConv, nkConv: var a = getConstExpr(m, n.sons[1]) if a == nil: return result = foldConv(n, a, check=n.kind == nkHiddenStdConv) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 93170e530..56746ce26 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -135,6 +135,13 @@ proc isStrangeArray(t: PType): bool = let t = t.skipTypes(abstractInst) 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, flags: TExprFlags): PNode = case n[0].sym.magic @@ -158,6 +165,12 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, of mProcCall: result = n 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: # error correction: result = n.sons[1] diff --git a/lib/system.nim b/lib/system.nim index 59faa83fb..51ac9cd69 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -228,7 +228,7 @@ type when defined(nimalias): {.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` ## 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 @@ -236,7 +236,7 @@ proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline.} = result.a = a 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]`` result.b = b @@ -2864,11 +2864,11 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} = when hostOS != "standalone": 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) 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 ## by `x`, a `splice`:idx: is performed: ## @@ -2884,8 +2884,7 @@ when hostOS != "standalone": spliceImpl(s, a, L, b) proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] = - ## slice operation for arrays. Negative indexes are **not** supported - ## because the array might have negative bounds. + ## slice operation for arrays. when low(a) < 0: {.error: "Slicing for arrays with negative indices is unsupported.".} 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] proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) = - ## slice assignment for arrays. Negative indexes are **not** supported - ## because the array might have negative bounds. + ## slice assignment for arrays. when low(a) < 0: {.error: "Slicing for arrays with negative indices is unsupported.".} 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") proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] = - ## slice operation for arrays. Negative indexes are **not** supported - ## because the array might have negative bounds. + ## slice operation for arrays. var L = ord(x.b) - ord(x.a) + 1 newSeq(result, L) for i in 0.. <L: result[i] = a[Idx(ord(x.a) + i)] proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) = - ## slice assignment for arrays. Negative indexes are **not** supported - ## because the array might have negative bounds. + ## slice assignment for arrays. var L = ord(x.b) - ord(x.a) + 1 if L == b.len: 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") 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 L = x.b-|s - a + 1 newSeq(result, L) for i in 0.. <L: result[i] = s[i + a] 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 ## by `x`, a `splice`:idx: is performed. var a = x.a-|s diff --git a/todo.txt b/todo.txt index e32ebf490..b2f1e28be 100644 --- a/todo.txt +++ b/todo.txt @@ -6,7 +6,6 @@ version 0.10.4 - make 'nil' work for 'add' and 'len' - add "all threads are blocked" detection to 'spawn' - overloading of '=' -- disallow negative indexing version 1.0 diff --git a/web/news.txt b/web/news.txt index 1b8ddd3ce..f1ce656a8 100644 --- a/web/news.txt +++ b/web/news.txt @@ -59,6 +59,12 @@ News echo x.T 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 ------------------ |