Merge branch 'devel' into jpoirier-realtimeGCTest

This commit is contained in:
Simon Hafner 2015-04-01 06:33:24 +05:00
commit a339cb5ed5
42 changed files with 672 additions and 409 deletions

View file

@ -529,7 +529,7 @@ type
TMagic* = enum # symbols that require compiler magic: TMagic* = enum # symbols that require compiler magic:
mNone, mNone,
mDefined, mDefinedInScope, mCompiles, mDefined, mDefinedInScope, mCompiles,
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof,
mEcho, mShallowCopy, mSlurp, mStaticExec, mEcho, mShallowCopy, mSlurp, mStaticExec,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst, mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray, mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
@ -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

@ -113,7 +113,7 @@ proc genMergeInfo*(m: BModule): PRope =
s.add("*/") s.add("*/")
result = s.toRope result = s.toRope
template `^`(pos: expr): expr = L.buf[pos] template `^`(pos: int): expr = L.buf[pos]
proc skipWhite(L: var TBaseLexer) = proc skipWhite(L: var TBaseLexer) =
var pos = L.bufpos var pos = L.bufpos

View file

@ -131,11 +131,10 @@ proc semNodeKindConstraints*(p: PNode): PNode =
result.strVal.add(ppEof) result.strVal.add(ppEof)
type type
TSideEffectAnalysis = enum TSideEffectAnalysis* = enum
seUnknown, seSideEffect, seNoSideEffect seUnknown, seSideEffect, seNoSideEffect
proc checkForSideEffects(n: PNode): TSideEffectAnalysis = proc checkForSideEffects*(n: PNode): TSideEffectAnalysis =
# XXX is 'raise' a side effect?
case n.kind case n.kind
of nkCallKinds: of nkCallKinds:
# only calls can produce side effects: # only calls can produce side effects:
@ -162,6 +161,8 @@ proc checkForSideEffects(n: PNode): TSideEffectAnalysis =
# an atom cannot produce a side effect: # an atom cannot produce a side effect:
result = seNoSideEffect result = seNoSideEffect
else: else:
# assume no side effect:
result = seNoSideEffect
for i in 0 .. <n.len: for i in 0 .. <n.len:
let ret = checkForSideEffects(n.sons[i]) let ret = checkForSideEffects(n.sons[i])
if ret == seSideEffect: return ret if ret == seSideEffect: return ret

View file

@ -241,9 +241,15 @@ proc isOperator(tok: TToken): bool =
proc isUnary(p: TParser): bool = proc isUnary(p: TParser): bool =
## Check if the current parser token is a unary operator ## Check if the current parser token is a unary operator
p.strongSpaces and p.tok.tokType in {tkOpr, tkDotDot} and if p.tok.tokType in {tkOpr, tkDotDot} and
p.tok.strongSpaceB == 0 and p.tok.strongSpaceB == 0 and
p.tok.strongSpaceA > 0 p.tok.strongSpaceA > 0:
# XXX change this after 0.10.4 is out
if p.strongSpaces:
result = true
else:
parMessage(p, warnDeprecated,
"will be parsed as unary operator; inconsistent spacing")
proc checkBinary(p: TParser) {.inline.} = proc checkBinary(p: TParser) {.inline.} =
## Check if the current parser token is a binary operator. ## Check if the current parser token is a binary operator.

View file

@ -201,7 +201,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
elif nfDotSetter in n.flags: elif nfDotSetter in n.flags:
internalAssert f.kind == nkIdent and n.sonsLen == 3 internalAssert f.kind == nkIdent and n.sonsLen == 3
let calleeName = newStrNode(nkStrLit, f.ident.s[0.. -2]).withInfo(n.info) let calleeName = newStrNode(nkStrLit,
f.ident.s[0..f.ident.s.len-2]).withInfo(n.info)
let callOp = newIdentNode(getIdent".=", n.info) let callOp = newIdentNode(getIdent".=", n.info)
n.sons[0..1] = [callOp, n[1], calleeName] n.sons[0..1] = [callOp, n[1], calleeName]
orig.sons[0..1] = [callOp, orig[1], calleeName] orig.sons[0..1] = [callOp, orig[1], calleeName]

View file

@ -26,7 +26,7 @@ type
POptionEntry* = ref TOptionEntry POptionEntry* = ref TOptionEntry
PProcCon* = ref TProcCon PProcCon* = ref TProcCon
TProcCon*{.final.} = object # procedure context; also used for top-level TProcCon* = object # procedure context; also used for top-level
# statements # statements
owner*: PSym # the symbol this context belongs to owner*: PSym # the symbol this context belongs to
resultSym*: PSym # the result symbol (if we are in a proc) resultSym*: PSym # the result symbol (if we are in a proc)
@ -36,6 +36,7 @@ type
# in standalone ``except`` and ``finally`` # in standalone ``except`` and ``finally``
next*: PProcCon # used for stacking procedure contexts next*: PProcCon # used for stacking procedure contexts
wasForwarded*: bool # whether the current proc has a separate header wasForwarded*: bool # whether the current proc has a separate header
bracketExpr*: PNode # current bracket expression (for ^ support)
TInstantiationPair* = object TInstantiationPair* = object
genericSym*: PSym genericSym*: PSym

View file

@ -71,11 +71,12 @@ proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
result.addSon(newNode(nkDotExpr, n.info, @[holder, n.sons[0]])) result.addSon(newNode(nkDotExpr, n.info, @[holder, n.sons[0]]))
for i in countup(1, n.len - 1): for i in countup(1, n.len - 1):
# of A, B: # of A, B:
var caseBranch = newNode(n[i].kind, n[i].info, n[i].sons[0 .. -2]) let ni = n[i]
var caseBranch = newNode(ni.kind, ni.info, ni.sons[0..ni.len-2])
let stmt = destroyFieldOrFields(c, n[i].lastSon, holder) let stmt = destroyFieldOrFields(c, ni.lastSon, holder)
if stmt == nil: if stmt == nil:
caseBranch.addSon(newNode(nkStmtList, n[i].info, @[])) caseBranch.addSon(newNode(nkStmtList, ni.info, @[]))
else: else:
caseBranch.addSon(stmt) caseBranch.addSon(stmt)
nonTrivialFields += stmt.len nonTrivialFields += stmt.len
@ -209,7 +210,7 @@ proc insertDestructors(c: PContext,
if j < totalVars - 1: if j < totalVars - 1:
var remainingVars = newNodeI(varSection.kind, info) var remainingVars = newNodeI(varSection.kind, info)
remainingVars.sons = varSection.sons[(j+1)..(-1)] remainingVars.sons = varSection.sons[(j+1)..varSection.len-1]
let (outer, inner) = insertDestructors(c, remainingVars) let (outer, inner) = insertDestructors(c, remainingVars)
if outer != nil: if outer != nil:
tryStmt.addSon(outer) tryStmt.addSon(outer)

View file

@ -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 ## returns nil if not a built-in subscript operator; also called for the
## checking of assignments ## checking of assignments
if sonsLen(n) == 1: if sonsLen(n) == 1:
var x = semDeref(c, n) let x = semDeref(c, n)
if x == nil: return nil if x == nil: return nil
result = newNodeIT(nkDerefExpr, x.info, x.typ) result = newNodeIT(nkDerefExpr, x.info, x.typ)
result.add(x[0]) result.add(x[0])
return return
checkMinSonsLen(n, 2) checkMinSonsLen(n, 2)
n.sons[0] = semExprWithType(c, n.sons[0]) 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 case arr.kind
of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString, of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
tyCString: tyCString:
if n.len != 2: return nil if n.len != 2: return nil
n.sons[0] = makeDeref(n.sons[0]) n.sons[0] = makeDeref(n.sons[0])
c.p.bracketExpr = n.sons[0]
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
n.sons[i] = semExprWithType(c, n.sons[i], n.sons[i] = semExprWithType(c, n.sons[i],
flags*{efInTypeof, efDetermineType}) flags*{efInTypeof, efDetermineType})
@ -1166,6 +1167,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
of tyTuple: of tyTuple:
checkSonsLen(n, 2) checkSonsLen(n, 2)
n.sons[0] = makeDeref(n.sons[0]) n.sons[0] = makeDeref(n.sons[0])
c.p.bracketExpr = n.sons[0]
# [] operator for tuples requires constant expression: # [] operator for tuples requires constant expression:
n.sons[1] = semConstExpr(c, n.sons[1]) n.sons[1] = semConstExpr(c, n.sons[1])
if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal}).kind in 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: else:
localError(n.info, errIndexTypesDoNotMatch) localError(n.info, errIndexTypesDoNotMatch)
result = n result = n
else: discard else:
c.p.bracketExpr = n.sons[0]
proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
let oldBracketExpr = c.p.bracketExpr
result = semSubscript(c, n, flags) result = semSubscript(c, n, flags)
if result == nil: if result == nil:
# overloaded [] operator: # overloaded [] operator:
result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]")) result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]"))
c.p.bracketExpr = oldBracketExpr
proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode = proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
var id = considerQuotedIdent(a[1]) var id = considerQuotedIdent(a[1])
@ -1249,11 +1254,15 @@ proc semAsgn(c: PContext, n: PNode): PNode =
of nkBracketExpr: of nkBracketExpr:
# a[i] = x # a[i] = x
# --> `[]=`(a, i, x) # --> `[]=`(a, i, x)
let oldBracketExpr = c.p.bracketExpr
a = semSubscript(c, a, {efLValue}) a = semSubscript(c, a, {efLValue})
if a == nil: if a == nil:
result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=") result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
add(result, n[1]) add(result, n[1])
return semExprNoType(c, result) result = semExprNoType(c, result)
c.p.bracketExpr = oldBracketExpr
return result
c.p.bracketExpr = oldBracketExpr
of nkCurlyExpr: of nkCurlyExpr:
# a{i} = x --> `{}=`(a, i, x) # a{i} = x --> `{}=`(a, i, x)
result = buildOverloadedSubscripts(n.sons[0], getIdent"{}=") result = buildOverloadedSubscripts(n.sons[0], getIdent"{}=")
@ -1895,7 +1904,8 @@ proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
of nkOfBranch, nkElse: checkInitialized(lastSon(n.sons[i]), ids, info) of nkOfBranch, nkElse: checkInitialized(lastSon(n.sons[i]), ids, info)
else: internalError(info, "checkInitialized") else: internalError(info, "checkInitialized")
of nkSym: of nkSym:
if tfNeedsInit in n.sym.typ.flags and n.sym.name.id notin ids: if {tfNotNil, tfNeedsInit} * n.sym.typ.flags != {} and
n.sym.name.id notin ids:
message(info, errGenerated, "field not initialized: " & n.sym.name.s) message(info, errGenerated, "field not initialized: " & n.sym.name.s)
else: internalError(info, "checkInitialized") else: internalError(info, "checkInitialized")

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

@ -130,6 +130,18 @@ proc semLocals(c: PContext, n: PNode): PNode =
result.add(a) result.add(a)
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode 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 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
@ -153,4 +165,35 @@ 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
# disallow negative indexing for now:
if not c.p.bracketExpr.isNil:
if isNegative(n.sons[1]) or (n.len > 2 and isNegative(n.sons[2])):
localError(n.info, "use '^' instead of '-'; negative indexing is obsolete")
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 else: result = n

View file

@ -1281,7 +1281,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
var tryStmt = newNodeI(nkTryStmt, n.sons[i].info) var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
var body = newNodeI(nkStmtList, n.sons[i].info) var body = newNodeI(nkStmtList, n.sons[i].info)
if i < n.sonsLen - 1: if i < n.sonsLen - 1:
body.sons = n.sons[(i+1)..(-1)] body.sons = n.sons[(i+1)..n.len-1]
tryStmt.addSon(body) tryStmt.addSon(body)
tryStmt.addSon(deferPart) tryStmt.addSon(deferPart)
n.sons[i] = semTry(c, tryStmt) n.sons[i] = semTry(c, tryStmt)

View file

@ -1175,6 +1175,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = semAnyRef(c, n, tyPtr, prev) result = semAnyRef(c, n, tyPtr, prev)
elif op.id == ord(wRef): elif op.id == ord(wRef):
result = semAnyRef(c, n, tyRef, prev) result = semAnyRef(c, n, tyRef, prev)
elif op.id == ord(wType):
checkSonsLen(n, 2)
let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
result = typExpr.typ.skipTypes({tyIter})
else: else:
result = semTypeExpr(c, n) result = semTypeExpr(c, n)
of nkWhenStmt: of nkWhenStmt:

View file

@ -590,7 +590,7 @@ proc firstOrd(t: PType): BiggestInt =
of tyUInt..tyUInt64: result = 0 of tyUInt..tyUInt64: result = 0
of tyEnum: of tyEnum:
# if basetype <> nil then return firstOrd of basetype # 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]) result = firstOrd(t.sons[0])
else: else:
assert(t.n.sons[0].kind == nkSym) assert(t.n.sons[0].kind == nkSym)

View file

@ -42,6 +42,7 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode = proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode =
let sym = newSym(skType, getIdent(name), t.owner, info) let sym = newSym(skType, getIdent(name), t.owner, info)
sym.typ = t
result = newSymNode(sym) result = newSymNode(sym)
result.typ = t result.typ = t

View file

@ -1008,7 +1008,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
if dest < 0: dest = c.getTemp(n.typ) if dest < 0: dest = c.getTemp(n.typ)
c.gABC(n, opcCallSite, dest) c.gABC(n, opcCallSite, dest)
of mNGenSym: genBinaryABC(c, n, dest, opcGenSym) of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI, mAbsI64: of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI,
mAbsI64, mDotDot:
c.genCall(n, dest) c.genCall(n, dest)
of mExpandToAst: of mExpandToAst:
if n.len != 2: if n.len != 2:

View file

@ -121,7 +121,7 @@ different; for this a special setter syntax is needed:
.. code-block:: nim .. code-block:: nim
type type
Socket* = object of RootObj Socket* = ref object of RootObj
FHost: int # cannot be accessed from the outside of the module FHost: int # cannot be accessed from the outside of the module
# the `F` prefix is a convention to avoid clashes since # the `F` prefix is a convention to avoid clashes since
# the accessors are named `host` # the accessors are named `host`
@ -134,8 +134,8 @@ different; for this a special setter syntax is needed:
## getter of hostAddr ## getter of hostAddr
s.FHost s.FHost
var var s: Socket
s: Socket new s
s.host = 34 # same as `host=`(s, 34) s.host = 34 # same as `host=`(s, 34)
@ -351,32 +351,32 @@ dispatch.
.. code-block:: nim .. code-block:: nim
type type
Expression = object of RootObj ## abstract base class for an expression Expression = ref object of RootObj ## abstract base class for an expression
Literal = object of Expression Literal = ref object of Expression
x: int x: int
PlusExpr = object of Expression PlusExpr = ref object of Expression
a, b: ref Expression a, b: Expression
method eval(e: ref Expression): int = method eval(e: Expression): int =
# override this base method # override this base method
quit "to override!" quit "to override!"
method eval(e: ref Literal): int = return e.x method eval(e: Literal): int = return e.x
method eval(e: ref PlusExpr): int = method eval(e: PlusExpr): int =
# watch out: relies on dynamic binding # watch out: relies on dynamic binding
result = eval(e.a) + eval(e.b) result = eval(e.a) + eval(e.b)
proc newLit(x: int): ref Literal = proc newLit(x: int): Literal =
new(result) new(result)
result.x = x result.x = x
proc newPlus(a, b: ref Expression): ref PlusExpr = proc newPlus(a, b: Expression): PlusExpr =
new(result) new(result)
result.a = a result.a = a
result.b = b result.b = b
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
In the example the constructors ``newLit`` and ``newPlus`` are procs In the example the constructors ``newLit`` and ``newPlus`` are procs
because they should use static binding, but ``eval`` is a method because it because they should use static binding, but ``eval`` is a method because it
@ -387,8 +387,8 @@ dispatching:
.. code-block:: nim .. code-block:: nim
type type
Thing = object of RootObj Thing = ref object of RootObj
Unit = object of Thing Unit = ref object of Thing
x: int x: int
method collide(a, b: Thing) {.inline.} = method collide(a, b: Thing) {.inline.} =
@ -400,8 +400,9 @@ dispatching:
method collide(a: Unit, b: Thing) {.inline.} = method collide(a: Unit, b: Thing) {.inline.} =
echo "2" echo "2"
var var a, b: Unit
a, b: Unit new a
new b
collide(a, b) # output: 2 collide(a, b) # output: 2

View file

@ -568,7 +568,7 @@ the ``of`` operator can be used to determine the object's type.
name*: string # the * means that `name` is accessible from other modules name*: string # the * means that `name` is accessible from other modules
age: int # no * means that the field is hidden age: int # no * means that the field is hidden
Student = object of Person # a student is a person Student = ref object of Person # a student is a person
id: int # with an id field id: int # with an id field
var var

View file

@ -56,11 +56,11 @@ Objects have access to their type at runtime. There is an
.. code-block:: nim .. code-block:: nim
type type
Person = object of RootObj Person = ref object of RootObj
name*: string # the * means that `name` is accessible from other modules name*: string # the * means that `name` is accessible from other modules
age: int # no * means that the field is hidden from other modules age: int # no * means that the field is hidden from other modules
Student = object of Person # Student inherits from Person Student = ref object of Person # Student inherits from Person
id: int # with an id field id: int # with an id field
var var
@ -69,6 +69,7 @@ Objects have access to their type at runtime. There is an
assert(student of Student) # is true assert(student of Student) # is true
# object construction: # object construction:
student = Student(name: "Anton", age: 5, id: 2) student = Student(name: "Anton", age: 5, id: 2)
echo student[]
Object fields that should be visible from outside the defining module have to Object fields that should be visible from outside the defining module have to
be marked by ``*``. In contrast to tuples, different object types are be marked by ``*``. In contrast to tuples, different object types are
@ -82,6 +83,9 @@ no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma
to introduce new object roots apart from ``system.RootObj``. (This is used to introduce new object roots apart from ``system.RootObj``. (This is used
in the GTK wrapper for instance.) in the GTK wrapper for instance.)
Ref objects should be used whenever inheritance is used. It isn't strictly
necessary, but with non-ref objects assignments such as ``let person: Person =
Student(id: 123)`` will truncate subclass fields.
**Note**: Composition (*has-a* relation) is often preferable to inheritance **Note**: Composition (*has-a* relation) is often preferable to inheritance
(*is-a* relation) for simple code reuse. Since objects are value types in (*is-a* relation) for simple code reuse. Since objects are value types in
@ -228,7 +232,7 @@ is needed:
.. code-block:: nim .. code-block:: nim
type type
Socket* = object of RootObj Socket* = ref object of RootObj
FHost: int # cannot be accessed from the outside of the module FHost: int # cannot be accessed from the outside of the module
# the `F` prefix is a convention to avoid clashes since # the `F` prefix is a convention to avoid clashes since
# the accessors are named `host` # the accessors are named `host`
@ -241,8 +245,8 @@ is needed:
## getter of hostAddr ## getter of hostAddr
s.FHost s.FHost
var var s: Socket
s: Socket new s
s.host = 34 # same as `host=`(s, 34) s.host = 34 # same as `host=`(s, 34)
(The example also shows ``inline`` procedures.) (The example also shows ``inline`` procedures.)
@ -313,8 +317,8 @@ dispatching:
.. code-block:: nim .. code-block:: nim
type type
Thing = object of RootObj Thing = ref object of RootObj
Unit = object of Thing Unit = ref object of Thing
x: int x: int
method collide(a, b: Thing) {.inline.} = method collide(a, b: Thing) {.inline.} =
@ -326,8 +330,9 @@ dispatching:
method collide(a: Unit, b: Thing) {.inline.} = method collide(a: Unit, b: Thing) {.inline.} =
echo "2" echo "2"
var var a, b: Unit
a, b: Unit new a
new b
collide(a, b) # output: 2 collide(a, b) # output: 2

View file

@ -253,16 +253,16 @@ proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
while true: while true:
while indexes[index] == -1: while indexes[index] == -1:
indexes[index] = initial[index] indexes[index] = initial[index]
index +=1 index += 1
if index == x.len: return if index == x.len: return
indexes[index] -=1 indexes[index] -= 1
for ni, i in indexes: for ni, i in indexes:
next[ni] = x[ni][i] next[ni] = x[ni][i]
var res: seq[T] var res: seq[T]
shallowCopy(res, next) shallowCopy(res, next)
result.add(res) result.add(res)
index = 0 index = 0
indexes[index] -=1 indexes[index] -= 1
proc nextPermutation*[T](x: var openarray[T]): bool {.discardable.} = proc nextPermutation*[T](x: var openarray[T]): bool {.discardable.} =
## Calculates the next lexicographic permutation, directly modifying ``x``. ## Calculates the next lexicographic permutation, directly modifying ``x``.

View file

@ -61,8 +61,8 @@ proc pasv(ftp: AsyncFtpClient) {.async.} =
assertReply(pasvMsg, "227") assertReply(pasvMsg, "227")
var betweenParens = captureBetween(pasvMsg.string, '(', ')') var betweenParens = captureBetween(pasvMsg.string, '(', ')')
var nums = betweenParens.split(',') var nums = betweenParens.split(',')
var ip = nums[0.. -3] var ip = nums[0.. ^3]
var port = nums[-2.. -1] var port = nums[^2.. ^1]
var properPort = port[0].parseInt()*256+port[1].parseInt() var properPort = port[0].parseInt()*256+port[1].parseInt()
await ftp.dsock.connect(ip.join("."), Port(properPort.toU16)) await ftp.dsock.connect(ip.join("."), Port(properPort.toU16))
ftp.dsockConnected = true ftp.dsockConnected = true

View file

@ -256,7 +256,7 @@ proc asyncSockHandleWrite(h: RootRef) =
# do nothing instead. # do nothing instead.
discard discard
elif bytesSent != sock.sendBuffer.len: elif bytesSent != sock.sendBuffer.len:
sock.sendBuffer = sock.sendBuffer[bytesSent .. -1] sock.sendBuffer = sock.sendBuffer[bytesSent .. ^1]
elif bytesSent == sock.sendBuffer.len: elif bytesSent == sock.sendBuffer.len:
sock.sendBuffer = "" sock.sendBuffer = ""
@ -550,7 +550,7 @@ proc send*(sock: AsyncSocket, data: string) =
sock.sendBuffer.add(data) sock.sendBuffer.add(data)
sock.deleg.mode = fmReadWrite sock.deleg.mode = fmReadWrite
elif bytesSent != data.len: elif bytesSent != data.len:
sock.sendBuffer.add(data[bytesSent .. -1]) sock.sendBuffer.add(data[bytesSent .. ^1])
sock.deleg.mode = fmReadWrite sock.deleg.mode = fmReadWrite
proc timeValFromMilliseconds(timeout = 500): Timeval = proc timeValFromMilliseconds(timeout = 500): Timeval =

View file

@ -241,8 +241,8 @@ proc pasv[T](ftp: FtpBase[T]) =
assertReply(pasvMsg, "227") assertReply(pasvMsg, "227")
var betweenParens = captureBetween(pasvMsg.string, '(', ')') var betweenParens = captureBetween(pasvMsg.string, '(', ')')
var nums = betweenParens.split(',') var nums = betweenParens.split(',')
var ip = nums[0.. -3] var ip = nums[0.. ^3]
var port = nums[-2.. -1] var port = nums[^2.. ^1]
var properPort = port[0].parseInt()*256+port[1].parseInt() var properPort = port[0].parseInt()*256+port[1].parseInt()
ftp.dsock.connect(ip.join("."), Port(properPort.toU16)) ftp.dsock.connect(ip.join("."), Port(properPort.toU16))
when T is AsyncSocket: when T is AsyncSocket:
@ -488,7 +488,7 @@ proc doUpload[T](ftp: FtpBase[T], async = false): bool =
if bytesSent == ftp.job.toStore.len: if bytesSent == ftp.job.toStore.len:
ftp.job.toStore = "" ftp.job.toStore = ""
elif bytesSent != ftp.job.toStore.len and bytesSent != 0: elif bytesSent != ftp.job.toStore.len and bytesSent != 0:
ftp.job.toStore = ftp.job.toStore[bytesSent .. -1] ftp.job.toStore = ftp.job.toStore[bytesSent .. ^1]
ftp.job.progress.inc(bytesSent) ftp.job.progress.inc(bytesSent)
ftp.job.oneSecond.inc(bytesSent) ftp.job.oneSecond.inc(bytesSent)
else: else:
@ -512,7 +512,7 @@ proc doUpload[T](ftp: FtpBase[T], async = false): bool =
if bytesSent == 0: if bytesSent == 0:
ftp.job.toStore.add(s) ftp.job.toStore.add(s)
elif bytesSent != s.len: elif bytesSent != s.len:
ftp.job.toStore.add(s[bytesSent .. -1]) ftp.job.toStore.add(s[bytesSent .. ^1])
len = bytesSent len = bytesSent
ftp.job.progress.inc(len) ftp.job.progress.inc(len)

View file

@ -227,7 +227,7 @@ proc parseResponse(s: Socket, getBody: bool, timeout: int): Response =
inc(linei, le) inc(linei, le)
# Status code # Status code
linei.inc skipWhitespace(line, linei) linei.inc skipWhitespace(line, linei)
result.status = line[linei .. -1] result.status = line[linei .. ^1]
parsedStatus = true parsedStatus = true
else: else:
# Parse headers # Parse headers
@ -238,7 +238,7 @@ proc parseResponse(s: Socket, getBody: bool, timeout: int): Response =
if line[linei] != ':': httpError("invalid headers") if line[linei] != ':': httpError("invalid headers")
inc(linei) # Skip : inc(linei) # Skip :
result.headers[name] = line[linei.. -1].strip() result.headers[name] = line[linei.. ^1].strip()
if not fullyRead: if not fullyRead:
httpError("Connection was closed before full request has been made") httpError("Connection was closed before full request has been made")
if getBody: if getBody:
@ -725,7 +725,7 @@ proc parseResponse(client: AsyncHttpClient,
inc(linei, le) inc(linei, le)
# Status code # Status code
linei.inc skipWhitespace(line, linei) linei.inc skipWhitespace(line, linei)
result.status = line[linei .. -1] result.status = line[linei .. ^1]
parsedStatus = true parsedStatus = true
else: else:
# Parse headers # Parse headers
@ -736,7 +736,7 @@ proc parseResponse(client: AsyncHttpClient,
if line[linei] != ':': httpError("invalid headers") if line[linei] != ':': httpError("invalid headers")
inc(linei) # Skip : inc(linei) # Skip :
result.headers[name] = line[linei.. -1].strip() result.headers[name] = line[linei.. ^1].strip()
if not fullyRead: if not fullyRead:
httpError("Connection was closed before full request has been made") httpError("Connection was closed before full request has been made")
if getBody: if getBody:

View file

@ -170,7 +170,7 @@ proc countFiles(filename: string): int =
if kind == pcFile: if kind == pcFile:
let llfn = name & ext & ExtSep let llfn = name & ext & ExtSep
if path.extractFilename.startsWith(llfn): if path.extractFilename.startsWith(llfn):
let numS = path.extractFilename[llfn.len .. -1] let numS = path.extractFilename[llfn.len .. ^1]
try: try:
let num = parseInt(numS) let num = parseInt(numS)
if num > result: if num > result:

View file

@ -222,13 +222,13 @@ type
set*{.magic: "Set".}[T] ## Generic type to construct bit sets. set*{.magic: "Set".}[T] ## Generic type to construct bit sets.
type type
Slice* {.final, pure.}[T] = object ## builtin slice type Slice*[T] = object ## builtin slice type
a*, b*: T ## the bounds a*, b*: T ## the bounds
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,28 +2864,27 @@ 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, x.b)
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:
## ##
## .. code-block:: nim ## .. code-block:: nim
## var s = "abcdef" ## var s = "abcdef"
## s[1 .. -2] = "xyz" ## s[1 .. ^2] = "xyz"
## assert s == "axyzf" ## assert s == "axyzf"
var a = x.a-|s var a = x.a
var L = x.b-|s - a + 1 var L = x.b - a + 1
if L == b.len: if L == b.len:
for i in 0 .. <L: s[i+a] = b[i] for i in 0 .. <L: s[i+a] = b[i]
else: else:
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,18 +2918,18 @@ 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
var L = x.b-|s - a + 1 var L = x.b - 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
var L = x.b-|s - a + 1 var L = x.b - a + 1
if L == b.len: if L == b.len:
for i in 0 .. <L: s[i+a] = b[i] for i in 0 .. <L: s[i+a] = b[i]
else: else:
@ -3247,4 +3243,12 @@ proc procCall*(x: expr) {.magic: "ProcCall".} =
## procCall someMethod(a, b) ## procCall someMethod(a, b)
discard 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.} {.pop.} #{.push warning[GcMem]: off.}

View file

@ -165,7 +165,7 @@ proc initGC() =
init(gch.tempStack) init(gch.tempStack)
init(gch.additionalRoots) init(gch.additionalRoots)
when withBitvectors: when withBitvectors:
Init(gch.allocated) init(gch.allocated)
init(gch.marked) init(gch.marked)
var var

36
tests/array/troof1.nim Normal file
View file

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

10
tests/array/troof2.nim Normal file
View file

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

8
tests/array/troof3.nim Normal file
View file

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

37
tests/array/troof4.nim Normal file
View file

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

View file

@ -7,6 +7,6 @@ discard """
proc test: string = proc test: string =
result = "blah" result = "blah"
result[1 .. -1] result[1 .. ^1]
echo test() echo test()

View file

@ -27,7 +27,7 @@ proc refExpr(exprNode: NimNode): string {.compileTime.} =
"expr" & $(exprNodes.len - 1) "expr" & $(exprNodes.len - 1)
proc derefExpr(exprRef: string): NimNode {.compileTime.} = proc derefExpr(exprRef: string): NimNode {.compileTime.} =
exprNodes[parseInt(exprRef[4 .. -1])] exprNodes[parseInt(exprRef[4 .. ^1])]
#=============================================================================== #===============================================================================
# Define a type that allows a callable expression to be mapped onto elements # Define a type that allows a callable expression to be mapped onto elements

View file

@ -0,0 +1,49 @@
# tests to see if a symbol returned from macros.getType() can
# be used as a type
import macros
macro testTypesym (t:stmt): expr =
var ty = t.getType
if ty.typekind == ntyTypedesc:
# skip typedesc get to the real type
ty = ty[1].getType
if ty.kind == nnkSym: return ty
assert ty.kind == nnkBracketExpr
assert ty[0].kind == nnkSym
result = ty[0]
return
type TestFN = proc(a,b:int):int
var iii: testTypesym(TestFN)
static: assert iii is TestFN
proc foo11 : testTypesym(void) =
echo "HI!"
static: assert foo11 is proc():void
var sss: testTypesym(seq[int])
static: assert sss is seq[int]
# very nice :>
static: assert array[2,int] is testTypesym(array[2,int])
static: assert(ref int is testTypesym(ref int))
static: assert(void is testTypesym(void))
macro tts2 (t:stmt, idx:int): expr =
var ty = t.getType
if ty.typekind == ntyTypedesc:
# skip typedesc get to the real type
ty = ty[1].getType
if ty.kind == nnkSym: return ty
assert ty.kind == nnkBracketExpr
return ty[idx.intval.int]
type TestFN2 = proc(a:int,b:float):string
static:
assert(tts2(TestFN2, 0) is TestFN2)
assert(tts2(TestFN2, 1) is string)
assert(tts2(TestFN2, 2) is int)
assert(tts2(TestFN2, 3) is float)

View file

@ -36,7 +36,7 @@ echo()
var myseq = @[1, 2, 3, 4, 5, 6] var myseq = @[1, 2, 3, 4, 5, 6]
myseq[0..2] = myseq[-3.. -1] myseq[0..2] = myseq[^3 .. ^1]
for x in items(myseq): stdout.write(x) for x in items(myseq): stdout.write(x)
echo() echo()
@ -46,7 +46,7 @@ echo mystr
mystr[4..4] = "u" mystr[4..4] = "u"
# test full replacement # test full replacement
mystr[.. -2] = "egerichtet" mystr[.. ^2] = "egerichtet"
echo mystr echo mystr
@ -54,6 +54,6 @@ mystr[0..2] = "ve"
echo mystr echo mystr
var s = "abcdef" var s = "abcdef"
s[1 .. -2] = "xyz" s[1 .. ^2] = "xyz"
assert s == "axyzf" assert s == "axyzf"

View file

@ -0,0 +1,14 @@
discard """
errormsg: "field not initialized: bar"
line: "13"
"""
# bug #2355
type
Foo = object
foo: string not nil
bar: string not nil
# Create instance without initializaing the `bar` field
var f = Foo(foo: "foo")
echo f.bar.isNil # true

View file

@ -205,7 +205,7 @@ proc findMainFile(dir: string): string =
var nimFiles = 0 var nimFiles = 0
for kind, file in os.walkDir(dir): for kind, file in os.walkDir(dir):
if kind == pcFile: if kind == pcFile:
if file.endsWith(cfgExt): return file[.. -(cfgExt.len+1)] & ".nim" if file.endsWith(cfgExt): return file[.. ^(cfgExt.len+1)] & ".nim"
elif file.endsWith(".nim"): elif file.endsWith(".nim"):
if result.len == 0: result = file if result.len == 0: result = file
inc nimFiles inc nimFiles

View file

@ -59,7 +59,7 @@ proc callCompiler(cmdTemplate, filename, options: string,
target: TTarget): TSpec = target: TTarget): TSpec =
let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target], let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
"options", options, "file", filename.quoteShell]) "options", options, "file", filename.quoteShell])
var p = startProcess(command=c[0], args=c[1.. -1], var p = startProcess(command=c[0], args=c[1.. ^1],
options={poStdErrToStdOut, poUseShell}) options={poStdErrToStdOut, poUseShell})
let outp = p.outputStream let outp = p.outputStream
var suc = "" var suc = ""
@ -284,7 +284,7 @@ proc main() =
let testsDir = "tests" & DirSep let testsDir = "tests" & DirSep
for kind, dir in walkDir(testsDir): for kind, dir in walkDir(testsDir):
assert testsDir.startsWith(testsDir) assert testsDir.startsWith(testsDir)
let cat = dir[testsDir.len .. -1] let cat = dir[testsDir.len .. ^1]
if kind == pcDir and cat notin ["testament", "testdata", "nimcache"]: if kind == pcDir and cat notin ["testament", "testdata", "nimcache"]:
processCategory(r, Category(cat), p.cmdLineRest.string) processCategory(r, Category(cat), p.cmdLineRest.string)
for a in AdditionalCategories: for a in AdditionalCategories:

View file

@ -1,20 +1,18 @@
version 0.10.4 version 0.10.4
============== ==============
- improve the parser; deal with echo $foo gotcha
- improve GC-unsafety warnings - improve GC-unsafety warnings
- make 'nil' work for 'add' and 'len' - make 'nil' work for 'add' and 'len'
- add "all threads are blocked" detection to 'spawn'
- overloading of '=' - overloading of '='
- disallow negative indexing
version 1.0 version 1.0
=========== ===========
- remove echo $foo gotcha
- add "all threads are blocked" detection to 'spawn'
- figure out why C++ bootstrapping is so much slower - figure out why C++ bootstrapping is so much slower
- nimsuggest: auto-completion needs to work in 'class' macros - nimsuggest: auto-completion needs to work in 'class' macros
- improve the docs for inheritance
- The bitwise 'not' operator will be renamed to 'bnot' to - The bitwise 'not' operator will be renamed to 'bnot' to
prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs! prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs!
- iterators always require a return type - iterators always require a return type

View file

@ -42,6 +42,33 @@ News
structure; for immediate macro parameters ``nkCall('addr', 'x')`` is structure; for immediate macro parameters ``nkCall('addr', 'x')`` is
produced instead of ``nkAddr('x')``. produced instead of ``nkAddr('x')``.
- ``concept`` is now a keyword and is used instead of ``generic``. - ``concept`` is now a keyword and is used instead of ``generic``.
- The ``inc``, ``dec``, ``+=``, ``-=`` builtins now produce 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
- **Negative indexing for slicing does not work anymore!** 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!
``a[0.. -1]`` now produces the empty string/sequence.
- The compiler now warns about code like ``foo +=1`` which uses inconsistent
spacing around binary operators. Later versions of the language will parse
these as unary operators instead so that ``echo $foo`` finally can do what
people expect it to do.
Language Additions Language Additions
@ -84,6 +111,9 @@ News
varOrConst(x) # "var" varOrConst(x) # "var"
varOrConst(45) # "const" 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 Library additions
----------------- -----------------