mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
fixes #2420; negative indexing for slicing is obsolete (breaking change!)
This commit is contained in:
@@ -201,7 +201,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
|
||||
elif nfDotSetter in n.flags:
|
||||
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)
|
||||
n.sons[0..1] = [callOp, n[1], calleeName]
|
||||
orig.sons[0..1] = [callOp, orig[1], calleeName]
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# included from sem.nim
|
||||
|
||||
# special marker values that indicates that we are
|
||||
# 1) AnalyzingDestructor: currently analyzing the type for destructor
|
||||
# 1) AnalyzingDestructor: currently analyzing the type for destructor
|
||||
# generation (needed for recursive types)
|
||||
# 2) DestructorIsTrivial: completed the analysis before and determined
|
||||
# that the type has a trivial destructor
|
||||
@@ -41,7 +41,7 @@ proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
|
||||
if t.kind != tyGenericBody:
|
||||
localError(n.info, errDestructorNotGenericEnough)
|
||||
return
|
||||
|
||||
|
||||
t.destructor = s
|
||||
# automatically insert calls to base classes' destructors
|
||||
if n.sons[bodyPos].kind != nkEmpty:
|
||||
@@ -71,17 +71,18 @@ proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
|
||||
result.addSon(newNode(nkDotExpr, n.info, @[holder, n.sons[0]]))
|
||||
for i in countup(1, n.len - 1):
|
||||
# of A, B:
|
||||
var caseBranch = newNode(n[i].kind, n[i].info, n[i].sons[0 .. -2])
|
||||
|
||||
let stmt = destroyFieldOrFields(c, n[i].lastSon, holder)
|
||||
let ni = n[i]
|
||||
var caseBranch = newNode(ni.kind, ni.info, ni.sons[0..ni.len-2])
|
||||
|
||||
let stmt = destroyFieldOrFields(c, ni.lastSon, holder)
|
||||
if stmt == nil:
|
||||
caseBranch.addSon(newNode(nkStmtList, n[i].info, @[]))
|
||||
caseBranch.addSon(newNode(nkStmtList, ni.info, @[]))
|
||||
else:
|
||||
caseBranch.addSon(stmt)
|
||||
nonTrivialFields += stmt.len
|
||||
|
||||
|
||||
result.addSon(caseBranch)
|
||||
|
||||
|
||||
# maybe no fields were destroyed?
|
||||
if nonTrivialFields == 0:
|
||||
result = nil
|
||||
@@ -107,7 +108,7 @@ proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode =
|
||||
proc generateDestructor(c: PContext, t: PType): PNode =
|
||||
## generate a destructor for a user-defined object or tuple type
|
||||
## returns nil if the destructor turns out to be trivial
|
||||
|
||||
|
||||
# XXX: This may be true for some C-imported types such as
|
||||
# Tposix_spawnattr
|
||||
if t.n == nil or t.n.sons == nil: return
|
||||
@@ -120,13 +121,13 @@ proc generateDestructor(c: PContext, t: PType): PNode =
|
||||
|
||||
proc instantiateDestructor(c: PContext, typ: PType): PType =
|
||||
# returns nil if a variable of type `typ` doesn't require a
|
||||
# destructor. Otherwise, returns the type, which holds the
|
||||
# destructor. Otherwise, returns the type, which holds the
|
||||
# destructor that must be used for the varialbe.
|
||||
# The destructor is either user-defined or automatically
|
||||
# generated by the compiler in a member-wise fashion.
|
||||
var t = skipTypes(typ, {tyConst, tyMutable}).skipGenericAlias
|
||||
let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base else: t
|
||||
|
||||
|
||||
if typeHoldingUserDefinition.destructor != nil:
|
||||
# XXX: This is not entirely correct for recursive types, but we need
|
||||
# it temporarily to hide the "destroy is already defined" problem
|
||||
@@ -135,7 +136,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
|
||||
return typeHoldingUserDefinition
|
||||
else:
|
||||
return nil
|
||||
|
||||
|
||||
t = t.skipTypes({tyGenericInst})
|
||||
case t.kind
|
||||
of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
|
||||
@@ -200,16 +201,16 @@ proc insertDestructors(c: PContext,
|
||||
varId = varSection[j][0]
|
||||
varTyp = varId.sym.typ
|
||||
info = varId.info
|
||||
|
||||
|
||||
if varTyp == nil or sfGlobal in varId.sym.flags: continue
|
||||
let destructableT = instantiateDestructor(c, varTyp)
|
||||
|
||||
|
||||
if destructableT != nil:
|
||||
var tryStmt = newNodeI(nkTryStmt, info)
|
||||
|
||||
if j < totalVars - 1:
|
||||
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)
|
||||
if outer != nil:
|
||||
tryStmt.addSon(outer)
|
||||
@@ -221,7 +222,7 @@ proc insertDestructors(c: PContext,
|
||||
else:
|
||||
result.inner = newNodeI(nkStmtList, info)
|
||||
tryStmt.addSon(result.inner)
|
||||
|
||||
|
||||
tryStmt.addSon(
|
||||
newNode(nkFinally, info, @[
|
||||
semStmt(c, newNode(nkCall, info, @[
|
||||
|
||||
@@ -167,10 +167,10 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
result.typ = n[1].typ
|
||||
of mDotDot:
|
||||
result = n
|
||||
# we only need to warnings here about negative indexing:
|
||||
if isNegative(n.sons[1]) or (n.len > 2 and isNegative(n.sons[2])):
|
||||
message(n.info, warnDeprecated,
|
||||
"use '^' instead of '-'; negative indexing")
|
||||
# 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]
|
||||
|
||||
@@ -1281,7 +1281,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
|
||||
var body = newNodeI(nkStmtList, n.sons[i].info)
|
||||
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(deferPart)
|
||||
n.sons[i] = semTry(c, tryStmt)
|
||||
|
||||
@@ -18,8 +18,8 @@ import sockets, os
|
||||
## This module implements an asynchronous event loop together with asynchronous
|
||||
## sockets which use this event loop.
|
||||
## It is akin to Python's asyncore module. Many modules that use sockets
|
||||
## have an implementation for this module, those modules should all have a
|
||||
## ``register`` function which you should use to add the desired objects to a
|
||||
## have an implementation for this module, those modules should all have a
|
||||
## ``register`` function which you should use to add the desired objects to a
|
||||
## dispatcher which you created so
|
||||
## that you can receive the events associated with that module's object.
|
||||
##
|
||||
@@ -27,19 +27,19 @@ import sockets, os
|
||||
## function in a while loop.
|
||||
##
|
||||
## **Note:** Most modules have tasks which need to be ran regularly, this is
|
||||
## why you should not call ``poll`` with a infinite timeout, or even a
|
||||
## why you should not call ``poll`` with a infinite timeout, or even a
|
||||
## very long one. In most cases the default timeout is fine.
|
||||
##
|
||||
## **Note:** This module currently only supports select(), this is limited by
|
||||
## FD_SETSIZE, which is usually 1024. So you may only be able to use 1024
|
||||
## sockets at a time.
|
||||
##
|
||||
##
|
||||
## Most (if not all) modules that use asyncio provide a userArg which is passed
|
||||
## on with the events. The type that you set userArg to must be inheriting from
|
||||
## ``RootObj``!
|
||||
##
|
||||
## **Note:** If you want to provide async ability to your module please do not
|
||||
## use the ``Delegate`` object, instead use ``AsyncSocket``. It is possible
|
||||
## **Note:** If you want to provide async ability to your module please do not
|
||||
## use the ``Delegate`` object, instead use ``AsyncSocket``. It is possible
|
||||
## that in the future this type's fields will not be exported therefore breaking
|
||||
## your code.
|
||||
##
|
||||
@@ -59,11 +59,11 @@ import sockets, os
|
||||
## socket which will give you the client which is connecting. You should then
|
||||
## set any events that you want to use on that client and add it to your dispatcher
|
||||
## using the ``register`` procedure.
|
||||
##
|
||||
##
|
||||
## An example ``handleAccept`` follows:
|
||||
##
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
##
|
||||
## var disp = newDispatcher()
|
||||
## ...
|
||||
## proc handleAccept(s: AsyncSocket) =
|
||||
@@ -74,7 +74,7 @@ import sockets, os
|
||||
## client.handleRead = ...
|
||||
## disp.register(client)
|
||||
## ...
|
||||
##
|
||||
##
|
||||
## For client sockets you should only be interested in the ``handleRead`` and
|
||||
## ``handleConnect`` events. The former gets called whenever the socket has
|
||||
## received messages and can be read from and the latter gets called whenever
|
||||
@@ -83,14 +83,14 @@ import sockets, os
|
||||
##
|
||||
## Getting a blocking client from an AsyncSocket
|
||||
## =============================================
|
||||
##
|
||||
##
|
||||
## If you need a asynchronous server socket but you wish to process the clients
|
||||
## synchronously then you can use the ``getSocket`` converter to get
|
||||
## a ``Socket`` from the ``AsyncSocket`` object, this can then be combined
|
||||
## with ``accept`` like so:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
##
|
||||
## proc handleAccept(s: AsyncSocket) =
|
||||
## var client: Socket
|
||||
## getSocket(s).accept(client)
|
||||
@@ -113,11 +113,11 @@ type
|
||||
handleWrite*: proc (h: RootRef) {.nimcall, gcsafe.}
|
||||
handleError*: proc (h: RootRef) {.nimcall, gcsafe.}
|
||||
hasDataBuffered*: proc (h: RootRef): bool {.nimcall, gcsafe.}
|
||||
|
||||
|
||||
open*: bool
|
||||
task*: proc (h: RootRef) {.nimcall, gcsafe.}
|
||||
mode*: FileMode
|
||||
|
||||
|
||||
Delegate* = ref DelegateObj
|
||||
|
||||
Dispatcher* = ref DispatcherObj
|
||||
@@ -144,7 +144,7 @@ type
|
||||
deleg: Delegate
|
||||
|
||||
SocketStatus* = enum
|
||||
SockIdle, SockConnecting, SockConnected, SockListening, SockClosed,
|
||||
SockIdle, SockConnecting, SockConnected, SockListening, SockClosed,
|
||||
SockUDPBound
|
||||
|
||||
{.deprecated: [TDelegate: DelegateObj, PDelegate: Delegate,
|
||||
@@ -176,8 +176,8 @@ proc newAsyncSocket(): AsyncSocket =
|
||||
result.lineBuffer = "".TaintedString
|
||||
result.sendBuffer = ""
|
||||
|
||||
proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
|
||||
protocol: Protocol = IPPROTO_TCP,
|
||||
proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
|
||||
protocol: Protocol = IPPROTO_TCP,
|
||||
buffered = true): AsyncSocket =
|
||||
## Initialises an AsyncSocket object. If a socket cannot be initialised
|
||||
## EOS is raised.
|
||||
@@ -236,7 +236,7 @@ proc asyncSockHandleWrite(h: RootRef) =
|
||||
if AsyncSocket(h).socket.isSSL and not
|
||||
AsyncSocket(h).socket.gotHandshake:
|
||||
return
|
||||
|
||||
|
||||
if AsyncSocket(h).info == SockConnecting:
|
||||
AsyncSocket(h).handleConnect(AsyncSocket(h))
|
||||
AsyncSocket(h).info = SockConnected
|
||||
@@ -256,10 +256,10 @@ proc asyncSockHandleWrite(h: RootRef) =
|
||||
# do nothing instead.
|
||||
discard
|
||||
elif bytesSent != sock.sendBuffer.len:
|
||||
sock.sendBuffer = sock.sendBuffer[bytesSent .. -1]
|
||||
sock.sendBuffer = sock.sendBuffer[bytesSent .. ^1]
|
||||
elif bytesSent == sock.sendBuffer.len:
|
||||
sock.sendBuffer = ""
|
||||
|
||||
|
||||
if AsyncSocket(h).handleWrite != nil:
|
||||
AsyncSocket(h).handleWrite(AsyncSocket(h))
|
||||
except OSError:
|
||||
@@ -284,7 +284,7 @@ when defined(ssl):
|
||||
else:
|
||||
# handshake will set socket's ``sslNoHandshake`` field.
|
||||
discard AsyncSocket(h).socket.handshake()
|
||||
|
||||
|
||||
|
||||
proc asyncSockTask(h: RootRef) =
|
||||
when defined(ssl):
|
||||
@@ -377,9 +377,9 @@ proc acceptAddr*(server: AsyncSocket, client: var AsyncSocket,
|
||||
|
||||
if c == invalidSocket: raiseSocketError(server.socket)
|
||||
c.setBlocking(false) # TODO: Needs to be tested.
|
||||
|
||||
|
||||
# deleg.open is set in ``toDelegate``.
|
||||
|
||||
|
||||
client.socket = c
|
||||
client.lineBuffer = "".TaintedString
|
||||
client.sendBuffer = ""
|
||||
@@ -393,7 +393,7 @@ proc accept*(server: AsyncSocket, client: var AsyncSocket) =
|
||||
proc acceptAddr*(server: AsyncSocket): tuple[sock: AsyncSocket,
|
||||
address: string] {.deprecated.} =
|
||||
## Equivalent to ``sockets.acceptAddr``.
|
||||
##
|
||||
##
|
||||
## **Deprecated since version 0.9.0:** Please use the function above.
|
||||
var client = newAsyncSocket()
|
||||
var address: string = ""
|
||||
@@ -441,17 +441,17 @@ proc isConnected*(s: AsyncSocket): bool =
|
||||
## Determines whether ``s`` is connected.
|
||||
return s.info == SockConnected
|
||||
proc isListening*(s: AsyncSocket): bool =
|
||||
## Determines whether ``s`` is listening for incoming connections.
|
||||
## Determines whether ``s`` is listening for incoming connections.
|
||||
return s.info == SockListening
|
||||
proc isConnecting*(s: AsyncSocket): bool =
|
||||
## Determines whether ``s`` is connecting.
|
||||
## Determines whether ``s`` is connecting.
|
||||
return s.info == SockConnecting
|
||||
proc isClosed*(s: AsyncSocket): bool =
|
||||
## Determines whether ``s`` has been closed.
|
||||
return s.info == SockClosed
|
||||
proc isSendDataBuffered*(s: AsyncSocket): bool =
|
||||
## Determines whether ``s`` has data waiting to be sent, i.e. whether this
|
||||
## socket's sendBuffer contains data.
|
||||
## socket's sendBuffer contains data.
|
||||
return s.sendBuffer.len != 0
|
||||
|
||||
proc setHandleWrite*(s: AsyncSocket,
|
||||
@@ -550,7 +550,7 @@ proc send*(sock: AsyncSocket, data: string) =
|
||||
sock.sendBuffer.add(data)
|
||||
sock.deleg.mode = fmReadWrite
|
||||
elif bytesSent != data.len:
|
||||
sock.sendBuffer.add(data[bytesSent .. -1])
|
||||
sock.sendBuffer.add(data[bytesSent .. ^1])
|
||||
sock.deleg.mode = fmReadWrite
|
||||
|
||||
proc timeValFromMilliseconds(timeout = 500): Timeval =
|
||||
@@ -561,10 +561,10 @@ proc timeValFromMilliseconds(timeout = 500): Timeval =
|
||||
|
||||
proc createFdSet(fd: var TFdSet, s: seq[Delegate], m: var int) =
|
||||
FD_ZERO(fd)
|
||||
for i in items(s):
|
||||
for i in items(s):
|
||||
m = max(m, int(i.fd))
|
||||
FD_SET(i.fd, fd)
|
||||
|
||||
|
||||
proc pruneSocketSet(s: var seq[Delegate], fd: var TFdSet) =
|
||||
var i = 0
|
||||
var L = s.len
|
||||
@@ -576,16 +576,16 @@ proc pruneSocketSet(s: var seq[Delegate], fd: var TFdSet) =
|
||||
inc(i)
|
||||
setLen(s, L)
|
||||
|
||||
proc select(readfds, writefds, exceptfds: var seq[Delegate],
|
||||
proc select(readfds, writefds, exceptfds: var seq[Delegate],
|
||||
timeout = 500): int =
|
||||
var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
|
||||
|
||||
|
||||
var rd, wr, ex: TFdSet
|
||||
var m = 0
|
||||
createFdSet(rd, readfds, m)
|
||||
createFdSet(wr, writefds, m)
|
||||
createFdSet(ex, exceptfds, m)
|
||||
|
||||
|
||||
if timeout != -1:
|
||||
result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), addr(tv)))
|
||||
else:
|
||||
@@ -599,7 +599,7 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool =
|
||||
## This function checks for events on all the delegates in the `PDispatcher`.
|
||||
## It then proceeds to call the correct event handler.
|
||||
##
|
||||
## This function returns ``True`` if there are file descriptors that are still
|
||||
## This function returns ``True`` if there are file descriptors that are still
|
||||
## open, otherwise ``False``. File descriptors that have been
|
||||
## closed are immediately removed from the dispatcher automatically.
|
||||
##
|
||||
@@ -611,7 +611,7 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool =
|
||||
var readDg, writeDg, errorDg: seq[Delegate] = @[]
|
||||
var len = d.delegates.len
|
||||
var dc = 0
|
||||
|
||||
|
||||
while dc < len:
|
||||
let deleg = d.delegates[dc]
|
||||
if (deleg.mode != fmWrite or deleg.mode != fmAppend) and deleg.open:
|
||||
@@ -625,20 +625,20 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool =
|
||||
# File/socket has been closed. Remove it from dispatcher.
|
||||
d.delegates[dc] = d.delegates[len-1]
|
||||
dec len
|
||||
|
||||
|
||||
d.delegates.setLen(len)
|
||||
|
||||
|
||||
var hasDataBufferedCount = 0
|
||||
for d in d.delegates:
|
||||
if d.hasDataBuffered(d.deleVal):
|
||||
hasDataBufferedCount.inc()
|
||||
d.handleRead(d.deleVal)
|
||||
if hasDataBufferedCount > 0: return true
|
||||
|
||||
|
||||
if readDg.len() == 0 and writeDg.len() == 0:
|
||||
## TODO: Perhaps this shouldn't return if errorDg has something?
|
||||
return false
|
||||
|
||||
|
||||
if select(readDg, writeDg, errorDg, timeout) != 0:
|
||||
for i in 0..len(d.delegates)-1:
|
||||
if i > len(d.delegates)-1: break # One delegate might've been removed.
|
||||
@@ -651,7 +651,7 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool =
|
||||
deleg.handleWrite(deleg.deleVal)
|
||||
if deleg notin errorDg:
|
||||
deleg.handleError(deleg.deleVal)
|
||||
|
||||
|
||||
# Execute tasks
|
||||
for i in items(d.delegates):
|
||||
i.task(i.deleVal)
|
||||
@@ -664,7 +664,7 @@ when isMainModule:
|
||||
|
||||
proc testConnect(s: AsyncSocket, no: int) =
|
||||
echo("Connected! " & $no)
|
||||
|
||||
|
||||
proc testRead(s: AsyncSocket, no: int) =
|
||||
echo("Reading! " & $no)
|
||||
var data = ""
|
||||
@@ -682,31 +682,31 @@ when isMainModule:
|
||||
var address = ""
|
||||
s.acceptAddr(client, address)
|
||||
echo("Accepted ", address)
|
||||
client.handleRead =
|
||||
client.handleRead =
|
||||
proc (s: AsyncSocket) =
|
||||
testRead(s, 2)
|
||||
disp.register(client)
|
||||
|
||||
proc main =
|
||||
var d = newDispatcher()
|
||||
|
||||
|
||||
var s = asyncSocket()
|
||||
s.connect("amber.tenthbit.net", Port(6667))
|
||||
s.handleConnect =
|
||||
s.handleConnect =
|
||||
proc (s: AsyncSocket) =
|
||||
testConnect(s, 1)
|
||||
s.handleRead =
|
||||
s.handleRead =
|
||||
proc (s: AsyncSocket) =
|
||||
testRead(s, 1)
|
||||
d.register(s)
|
||||
|
||||
|
||||
var server = asyncSocket()
|
||||
server.handleAccept =
|
||||
proc (s: AsyncSocket) =
|
||||
proc (s: AsyncSocket) =
|
||||
testAccept(s, d, 78)
|
||||
server.bindAddr(Port(5555))
|
||||
server.listen()
|
||||
d.register(server)
|
||||
|
||||
|
||||
while d.poll(-1): discard
|
||||
main()
|
||||
|
||||
@@ -2865,7 +2865,7 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} =
|
||||
when hostOS != "standalone":
|
||||
proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
|
||||
## 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) =
|
||||
## slice assignment for strings. If
|
||||
@@ -2876,8 +2876,8 @@ when hostOS != "standalone":
|
||||
## var s = "abcdef"
|
||||
## s[1 .. -2] = "xyz"
|
||||
## assert s == "axyzf"
|
||||
var a = x.a-|s
|
||||
var L = x.b-|s - a + 1
|
||||
var a = x.a
|
||||
var L = x.b - a + 1
|
||||
if L == b.len:
|
||||
for i in 0 .. <L: s[i+a] = b[i]
|
||||
else:
|
||||
@@ -2919,8 +2919,8 @@ proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) =
|
||||
|
||||
proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] =
|
||||
## slice operation for sequences.
|
||||
var a = x.a-|s
|
||||
var L = x.b-|s - a + 1
|
||||
var a = x.a
|
||||
var L = x.b - a + 1
|
||||
newSeq(result, L)
|
||||
for i in 0.. <L: result[i] = s[i + a]
|
||||
|
||||
@@ -2928,8 +2928,8 @@ proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) =
|
||||
## slice assignment for sequences. If
|
||||
## ``b.len`` is not exactly the number of elements that are referred to
|
||||
## by `x`, a `splice`:idx: is performed.
|
||||
var a = x.a-|s
|
||||
var L = x.b-|s - a + 1
|
||||
var a = x.a
|
||||
var L = x.b - a + 1
|
||||
if L == b.len:
|
||||
for i in 0 .. <L: s[i+a] = b[i]
|
||||
else:
|
||||
|
||||
@@ -59,11 +59,12 @@ News
|
||||
echo x.T
|
||||
inc x
|
||||
|
||||
- **Negative indexing for slicing is deprecated and will be removed in the
|
||||
next version of the language.** Instead of ``a[0.. -1]`` you can
|
||||
- **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
|
||||
|
||||
Reference in New Issue
Block a user