Merge branch 'devel' into jpoirier-realtimeGCTest
This commit is contained in:
commit
a339cb5ed5
42 changed files with 672 additions and 409 deletions
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 & ')')
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
23
doc/tut2.txt
23
doc/tut2.txt
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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``.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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.}
|
||||||
|
|
|
||||||
|
|
@ -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
36
tests/array/troof1.nim
Normal 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
10
tests/array/troof2.nim
Normal 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
8
tests/array/troof3.nim
Normal 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
37
tests/array/troof4.nim
Normal 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)
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
49
tests/macros/typesapi2.nim
Normal file
49
tests/macros/typesapi2.nim
Normal 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)
|
||||||
|
|
||||||
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
||||||
14
tests/notnil/tnotnil_in_objconstr.nim
Normal file
14
tests/notnil/tnotnil_in_objconstr.nim
Normal 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
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
6
todo.txt
6
todo.txt
|
|
@ -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
|
||||||
|
|
|
||||||
30
web/news.txt
30
web/news.txt
|
|
@ -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
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue