diff options
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 4 | ||||
-rw-r--r-- | compiler/ccgmerge.nim | 24 | ||||
-rw-r--r-- | compiler/jsgen.nim | 4 | ||||
-rw-r--r-- | compiler/parampatterns.nim | 7 | ||||
-rw-r--r-- | compiler/semdata.nim | 55 | ||||
-rw-r--r-- | compiler/semexprs.nim | 17 | ||||
-rw-r--r-- | compiler/semmagic.nim | 30 | ||||
-rw-r--r-- | compiler/types.nim | 2 | ||||
-rw-r--r-- | lib/system.nim | 12 | ||||
-rw-r--r-- | tests/array/troof1.nim | 36 | ||||
-rw-r--r-- | tests/array/troof2.nim | 10 | ||||
-rw-r--r-- | tests/array/troof3.nim | 8 | ||||
-rw-r--r-- | tests/array/troof4.nim | 37 | ||||
-rw-r--r-- | web/news.txt | 19 |
15 files changed, 211 insertions, 56 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index d94f09ccb..b82a3887d 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -529,7 +529,7 @@ type TMagic* = enum # symbols that require compiler magic: mNone, mDefined, mDefinedInScope, mCompiles, - mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, + mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof, mEcho, mShallowCopy, mSlurp, mStaticExec, mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst, mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index e19341db5..a280abc31 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1735,9 +1735,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mReset: genReset(p, e) of mEcho: genEcho(p, e[1].skipConv) of mArrToSeq: genArrToSeq(p, e, d) - of mNLen..mNError: - localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s) - of mSlurp..mQuoteAst: + of mNLen..mNError, mSlurp..mQuoteAst: localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s) of mSpawn: let n = lowerings.wrapProcForSpawn(p.module.module, e, e.typ, nil, nil) diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index f4f837834..5057b9ff1 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -94,7 +94,7 @@ proc writeIntSet(a: IntSet, s: var string) = encodeVInt(x, s) inc i s.add('}') - + proc genMergeInfo*(m: BModule): PRope = if optSymbolFiles notin gGlobalOptions: return nil var s = "/*\tNIM_merge_INFO:" @@ -113,7 +113,7 @@ proc genMergeInfo*(m: BModule): PRope = s.add("*/") result = s.toRope -template `^`(pos: expr): expr = L.buf[pos] +template `^`(pos: int): expr = L.buf[pos] proc skipWhite(L: var TBaseLexer) = var pos = L.bufpos @@ -132,7 +132,7 @@ proc skipUntilCmd(L: var TBaseLexer) = of CR: pos = nimlexbase.handleCR(L, pos) of LF: pos = nimlexbase.handleLF(L, pos) of '\0': break - of '/': + of '/': if ^(pos+1) == '*' and ^(pos+2) == '\t': inc pos, 3 break @@ -145,7 +145,7 @@ proc atEndMark(buf: cstring, pos: int): bool = while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s result = s == NimMergeEndMark.len -proc readVerbatimSection(L: var TBaseLexer): PRope = +proc readVerbatimSection(L: var TBaseLexer): PRope = var pos = L.bufpos var buf = L.buf var r = newStringOfCap(30_000) @@ -162,7 +162,7 @@ proc readVerbatimSection(L: var TBaseLexer): PRope = of '\0': internalError("ccgmerge: expected: " & NimMergeEndMark) break - else: + else: if atEndMark(buf, pos): inc pos, NimMergeEndMark.len break @@ -181,7 +181,7 @@ proc readKey(L: var TBaseLexer, result: var string) = if buf[pos] != ':': internalError("ccgmerge: ':' expected") L.bufpos = pos + 1 # skip ':' -proc newFakeType(id: int): PType = +proc newFakeType(id: int): PType = new(result) result.id = id @@ -227,8 +227,8 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) = when not defined(nimhygiene): {.pragma: inject.} - -template withCFile(cfilename: string, body: stmt) {.immediate.} = + +template withCFile(cfilename: string, body: stmt) {.immediate.} = var s = llStreamOpen(cfilename, fmRead) if s == nil: return var L {.inject.}: TBaseLexer @@ -239,7 +239,7 @@ template withCFile(cfilename: string, body: stmt) {.immediate.} = if ^L.bufpos == '\0': break body closeBaseLexer(L) - + proc readMergeInfo*(cfilename: string, m: BModule) = ## reads the merge meta information into `m`. withCFile(cfilename): @@ -257,7 +257,7 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) = ## reads the merge sections into `m`. withCFile(cfilename): readKey(L, k) - if k == "NIM_merge_INFO": + if k == "NIM_merge_INFO": discard elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/': inc(L.bufpos, 2) @@ -283,7 +283,7 @@ proc mergeRequired*(m: BModule): bool = #echo "not empty: ", i, " ", ropeToStr(m.s[i]) return true for i in low(TCProcSection)..high(TCProcSection): - if m.initProc.s(i) != nil: + if m.initProc.s(i) != nil: #echo "not empty: ", i, " ", ropeToStr(m.initProc.s[i]) return true @@ -291,7 +291,7 @@ proc mergeFiles*(cfilename: string, m: BModule) = ## merges the C file with the old version on hard disc. var old: TMergeSections readMergeSections(cfilename, old) - # do the merge; old section before new section: + # do the merge; old section before new section: for i in low(TCFileSection)..high(TCFileSection): m.s[i] = con(old.f[i], m.s[i]) for i in low(TCProcSection)..high(TCProcSection): diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 4e0e732a5..563f0c866 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1371,13 +1371,11 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true") of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]") of mInSet: binaryExpr(p, n, r, "", "($1[$2] != undefined)") - of mNLen..mNError: - localError(n.info, errCannotGenerateCodeForX, n.sons[0].sym.name.s) of mNewSeq: genNewSeq(p, n) of mOf: genOf(p, n, r) of mReset: genReset(p, n) of mEcho: genEcho(p, n, r) - of mSlurp, mStaticExec: + of mNLen..mNError, mSlurp, mStaticExec: localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s) of mCopyStr: binaryExpr(p, n, r, "", "($1.slice($2))") of mCopyStrLast: ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))") diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 8c0875ab1..3f67005b9 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -131,11 +131,10 @@ proc semNodeKindConstraints*(p: PNode): PNode = result.strVal.add(ppEof) type - TSideEffectAnalysis = enum + TSideEffectAnalysis* = enum seUnknown, seSideEffect, seNoSideEffect -proc checkForSideEffects(n: PNode): TSideEffectAnalysis = - # XXX is 'raise' a side effect? +proc checkForSideEffects*(n: PNode): TSideEffectAnalysis = case n.kind of nkCallKinds: # only calls can produce side effects: @@ -162,6 +161,8 @@ proc checkForSideEffects(n: PNode): TSideEffectAnalysis = # an atom cannot produce a side effect: result = seNoSideEffect else: + # assume no side effect: + result = seNoSideEffect for i in 0 .. <n.len: let ret = checkForSideEffects(n.sons[i]) if ret == seSideEffect: return ret diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 27d441000..9b5d788af 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -9,13 +9,13 @@ ## This module contains the data structures for the semantic checking phase. -import +import strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab, - wordrecg, - ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, + wordrecg, + ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef -type +type TOptionEntry* = object of lists.TListEntry # entries to put on a # stack for pragma parsing options*: TOptions @@ -26,7 +26,7 @@ type POptionEntry* = ref TOptionEntry PProcCon* = ref TProcCon - TProcCon*{.final.} = object # procedure context; also used for top-level + TProcCon* = object # procedure context; also used for top-level # statements owner*: PSym # the symbol this context belongs to resultSym*: PSym # the result symbol (if we are in a proc) @@ -36,12 +36,13 @@ type # in standalone ``except`` and ``finally`` next*: PProcCon # used for stacking procedure contexts wasForwarded*: bool # whether the current proc has a separate header - + bracketExpr*: PNode # current bracket expression (for ^ support) + TInstantiationPair* = object genericSym*: PSym inst*: PInstantiation - TExprFlag* = enum + TExprFlag* = enum efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType, efAllowDestructor, efWantValue, efOperand, efNoSemCheck TExprFlags* = set[TExprFlag] @@ -57,7 +58,7 @@ type # this is used so that generic instantiations # can access private object fields instCounter*: int # to prevent endless instantiations - + ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot # store this info in the syms themselves!) inTypeClass*: int # > 0 if we are in a user-defined type class @@ -95,7 +96,7 @@ type instDeepCopy*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo): PSym {.nimcall.} - + proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = result.genericSym = s result.inst = inst @@ -127,7 +128,7 @@ proc popOwner*() var gOwners*: seq[PSym] = @[] -proc getCurrOwner(): PSym = +proc getCurrOwner(): PSym = # owner stack (used for initializing the # owner field of syms) # the documentation comment always gets @@ -135,19 +136,19 @@ proc getCurrOwner(): PSym = # BUGFIX: global array is needed! result = gOwners[high(gOwners)] -proc pushOwner(owner: PSym) = +proc pushOwner(owner: PSym) = add(gOwners, owner) -proc popOwner() = +proc popOwner() = var length = len(gOwners) if length > 0: setLen(gOwners, length - 1) else: internalError("popOwner") -proc lastOptionEntry(c: PContext): POptionEntry = +proc lastOptionEntry(c: PContext): POptionEntry = result = POptionEntry(c.optionStack.tail) -proc pushProcCon*(c: PContext, owner: PSym) {.inline.} = - if owner == nil: +proc pushProcCon*(c: PContext, owner: PSym) {.inline.} = + if owner == nil: internalError("owner is nil") return var x: PProcCon @@ -158,7 +159,7 @@ proc pushProcCon*(c: PContext, owner: PSym) {.inline.} = proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next -proc newOptionEntry(): POptionEntry = +proc newOptionEntry(): POptionEntry = new(result) result.options = gOptions result.defaultCC = ccDefault @@ -182,8 +183,8 @@ proc newContext(module: PSym): PContext = proc inclSym(sq: var TSymSeq, s: PSym) = var L = len(sq) - for i in countup(0, L - 1): - if sq[i].id == s.id: return + for i in countup(0, L - 1): + if sq[i].id == s.id: return setLen(sq, L + 1) sq[L] = s @@ -193,20 +194,20 @@ proc addConverter*(c: PContext, conv: PSym) = proc addPattern*(c: PContext, p: PSym) = inclSym(c.patterns, p) -proc newLib(kind: TLibKind): PLib = +proc newLib(kind: TLibKind): PLib = new(result) result.kind = kind #initObjectSet(result.syms) - + proc addToLib(lib: PLib, sym: PSym) = #if sym.annex != nil and not isGenericRoutine(sym): # LocalError(sym.info, errInvalidPragma) sym.annex = lib -proc makePtrType(c: PContext, baseType: PType): PType = +proc makePtrType(c: PContext, baseType: PType): PType = result = newTypeS(tyPtr, c) addSonSkipIntLit(result, baseType.assertNotNil) -proc makeVarType(c: PContext, baseType: PType): PType = +proc makeVarType(c: PContext, baseType: PType): PType = result = newTypeS(tyVar, c) addSonSkipIntLit(result, baseType.assertNotNil) @@ -286,7 +287,7 @@ proc errorNode*(c: PContext, n: PNode): PNode = result = newNodeI(nkEmpty, n.info) result.typ = errorType(c) -proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) = +proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) = dest.kind = kind dest.owner = getCurrOwner() dest.size = - 1 @@ -311,13 +312,13 @@ proc illFormedAst*(n: PNode) = proc illFormedAstLocal*(n: PNode) = localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments})) -proc checkSonsLen*(n: PNode, length: int) = +proc checkSonsLen*(n: PNode, length: int) = if sonsLen(n) != length: illFormedAst(n) - -proc checkMinSonsLen*(n: PNode, length: int) = + +proc checkMinSonsLen*(n: PNode, length: int) = if sonsLen(n) < length: illFormedAst(n) -proc isTopLevel*(c: PContext): bool {.inline.} = +proc isTopLevel*(c: PContext): bool {.inline.} = result = c.currentScope.depthLevel <= 2 proc experimentalMode*(c: PContext): bool {.inline.} = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a56de1028..bc7303266 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1133,19 +1133,20 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = ## returns nil if not a built-in subscript operator; also called for the ## checking of assignments if sonsLen(n) == 1: - var x = semDeref(c, n) + let x = semDeref(c, n) if x == nil: return nil result = newNodeIT(nkDerefExpr, x.info, x.typ) result.add(x[0]) return checkMinSonsLen(n, 2) n.sons[0] = semExprWithType(c, n.sons[0]) - var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef}) + let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef}) case arr.kind of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString, tyCString: if n.len != 2: return nil n.sons[0] = makeDeref(n.sons[0]) + c.p.bracketExpr = n.sons[0] for i in countup(1, sonsLen(n) - 1): n.sons[i] = semExprWithType(c, n.sons[i], flags*{efInTypeof, efDetermineType}) @@ -1166,6 +1167,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = of tyTuple: checkSonsLen(n, 2) n.sons[0] = makeDeref(n.sons[0]) + c.p.bracketExpr = n.sons[0] # [] operator for tuples requires constant expression: n.sons[1] = semConstExpr(c, n.sons[1]) if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal}).kind in @@ -1176,13 +1178,16 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = else: localError(n.info, errIndexTypesDoNotMatch) result = n - else: discard + else: + c.p.bracketExpr = n.sons[0] proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = + let oldBracketExpr = c.p.bracketExpr result = semSubscript(c, n, flags) if result == nil: # overloaded [] operator: result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]")) + c.p.bracketExpr = oldBracketExpr proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode = var id = considerQuotedIdent(a[1]) @@ -1249,11 +1254,15 @@ proc semAsgn(c: PContext, n: PNode): PNode = of nkBracketExpr: # a[i] = x # --> `[]=`(a, i, x) + let oldBracketExpr = c.p.bracketExpr a = semSubscript(c, a, {efLValue}) if a == nil: result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=") add(result, n[1]) - return semExprNoType(c, result) + result = semExprNoType(c, result) + c.p.bracketExpr = oldBracketExpr + return result + c.p.bracketExpr = oldBracketExpr of nkCurlyExpr: # a{i} = x --> `{}=`(a, i, x) result = buildOverloadedSubscripts(n.sons[0], getIdent"{}=") diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 3c9784152..93170e530 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -130,6 +130,11 @@ proc semLocals(c: PContext, n: PNode): PNode = result.add(a) proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode + +proc isStrangeArray(t: PType): bool = + let t = t.skipTypes(abstractInst) + result = t.kind == tyArray and t.firstOrd != 0 + proc magicsAfterOverloadResolution(c: PContext, n: PNode, flags: TExprFlags): PNode = case n[0].sym.magic @@ -153,4 +158,29 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, of mProcCall: result = n result.typ = n[1].typ + of mRoof: + # error correction: + result = n.sons[1] + if c.p.bracketExpr.isNil: + localError(n.info, "no surrounding array access context for '^'") + elif c.p.bracketExpr.checkForSideEffects != seNoSideEffect: + localError(n.info, "invalid context for '^' as '$#' has side effects" % + renderTree(c.p.bracketExpr)) + elif c.p.bracketExpr.typ.isStrangeArray: + localError(n.info, "invalid context for '^' as len!=high+1 for '$#'" % + renderTree(c.p.bracketExpr)) + else: + # ^x is rewritten to: len(a)-x + let lenExpr = newNodeI(nkCall, n.info) + lenExpr.add newIdentNode(getIdent"len", n.info) + lenExpr.add c.p.bracketExpr + let lenExprB = semExprWithType(c, lenExpr) + if lenExprB.typ.isNil or not isOrdinalType(lenExprB.typ): + localError(n.info, "'$#' has to be of an ordinal type for '^'" % + renderTree(lenExpr)) + else: + result = newNodeIT(nkCall, n.info, getSysType(tyInt)) + result.add newSymNode(createMagic("-", mSubI), n.info) + result.add lenExprB + result.add n.sons[1] else: result = n diff --git a/compiler/types.nim b/compiler/types.nim index f4ac4daea..153c26a42 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -590,7 +590,7 @@ proc firstOrd(t: PType): BiggestInt = of tyUInt..tyUInt64: result = 0 of tyEnum: # if basetype <> nil then return firstOrd of basetype - if (sonsLen(t) > 0) and (t.sons[0] != nil): + if sonsLen(t) > 0 and t.sons[0] != nil: result = firstOrd(t.sons[0]) else: assert(t.n.sons[0].kind == nkSym) diff --git a/lib/system.nim b/lib/system.nim index 75d1d40a6..59faa83fb 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -222,8 +222,8 @@ type set*{.magic: "Set".}[T] ## Generic type to construct bit sets. type - Slice* {.final, pure.}[T] = object ## builtin slice type - a*, b*: T ## the bounds + Slice*[T] = object ## builtin slice type + a*, b*: T ## the bounds when defined(nimalias): {.deprecated: [TSlice: Slice].} @@ -3247,4 +3247,12 @@ proc procCall*(x: expr) {.magic: "ProcCall".} = ## procCall someMethod(a, b) discard +proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} = + ## builtin `roof`:idx: operator that can be used for convenient array access. + ## ``a[^x]`` is rewritten to ``a[a.len-x]``. However currently the ``a`` + ## expression must not have side effects for this to compile. Note that since + ## this is a builtin, it automatically works for all kinds of + ## overloaded ``[]`` or ``[]=`` accessors. + discard + {.pop.} #{.push warning[GcMem]: off.} diff --git a/tests/array/troof1.nim b/tests/array/troof1.nim new file mode 100644 index 000000000..96669a121 --- /dev/null +++ b/tests/array/troof1.nim @@ -0,0 +1,36 @@ +discard """ + output: '''@[2, 3, 4]321 +9.0 4.0 +(a: 1.0, b: 2.0, c: 8.0)2.0''' +""" + +proc foo[T](x, y: T): T = x + +var a = @[1, 2, 3, 4] +var b: array[3, array[2, float]] = [[1.0,2], [3.0,4], [8.0,9]] +echo a[1.. ^1], a[^2], a[^3], a[^4] +echo b[^1][^1], " ", (b[^2]).foo(b[^1])[^1] + +type + MyArray = object + a, b, c: float + +var + ma = MyArray(a: 1.0, b: 2.0, c: 3.0) + +proc len(x: MyArray): int = 3 + +proc `[]=`(x: var MyArray; idx: range[0..2]; val: float) = + case idx + of 0: x.a = val + of 1: x.b = val + of 2: x.c = val + +proc `[]`(x: var MyArray; idx: range[0..2]): float = + case idx + of 0: result = x.a + of 1: result = x.b + of 2: result = x.c + +ma[^1] = 8.0 +echo ma, ma[^2] diff --git a/tests/array/troof2.nim b/tests/array/troof2.nim new file mode 100644 index 000000000..d4c1a4982 --- /dev/null +++ b/tests/array/troof2.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "invalid context for '^' as 'foo()' has side effects" + line: "9" +""" + +proc foo(): seq[int] = + echo "ha" + +let f = foo()[^1] + diff --git a/tests/array/troof3.nim b/tests/array/troof3.nim new file mode 100644 index 000000000..4b6e22223 --- /dev/null +++ b/tests/array/troof3.nim @@ -0,0 +1,8 @@ +discard """ + errormsg: "invalid context for '^' as len!=high+1 for 'a'" + line: "8" +""" + +var a: array[1..3, string] + +echo a[^1] diff --git a/tests/array/troof4.nim b/tests/array/troof4.nim new file mode 100644 index 000000000..7a262d9de --- /dev/null +++ b/tests/array/troof4.nim @@ -0,0 +1,37 @@ +discard """ + errormsg: "no surrounding array access context for '^'" + line: "37" +""" + +proc foo[T](x, y: T): T = x + +var a = @[1, 2, 3, 4] +var b: array[3, array[2, float]] = [[1.0,2], [3.0,4], [8.0,9]] +echo a[1.. ^1], a[^2], a[^3], a[^4] +echo b[^1][^1], " ", (b[^2]).foo(b[^1])[^1] + +type + MyArray = object + a, b, c: float + +var + ma = MyArray(a: 1.0, b: 2.0, c: 3.0) + +proc len(x: MyArray): int = 3 + +proc `[]=`(x: var MyArray; idx: range[0..2]; val: float) = + case idx + of 0: x.a = val + of 1: x.b = val + of 2: x.c = val + +proc `[]`(x: var MyArray; idx: range[0..2]): float = + case idx + of 0: result = x.a + of 1: result = x.b + of 2: result = x.c + +ma[^1] = 8.0 +echo ma, ma[^2] + +echo(^1) diff --git a/web/news.txt b/web/news.txt index 08a3cd6f5..1b8ddd3ce 100644 --- a/web/news.txt +++ b/web/news.txt @@ -42,6 +42,22 @@ News structure; for immediate macro parameters ``nkCall('addr', 'x')`` is produced instead of ``nkAddr('x')``. - ``concept`` is now a keyword and is used instead of ``generic``. + - The ``inc``, ``dec``, ``+=``, ``-=`` builtins now produces OverflowError + exceptions. This means code like the following: + + .. code-block:: nim + var x = low(T) + while x <= high(T): + echo x + inc x + + Needs to be replaced by something like this: + + .. code-block:: nim + var x = low(T).int + while x <= high(T).int: + echo x.T + inc x Language Additions @@ -84,6 +100,9 @@ News varOrConst(x) # "var" varOrConst(45) # "const" + - Array and seq indexing can now use the builtin ``^`` operator to access + things from backwards: ``a[^1]`` is like Python's ``a[-1]``. + Library additions ----------------- |