fixes #2420; negative indexing for slicing is obsolete (breaking change!)

This commit is contained in:
Araq 2015-03-28 00:15:04 +01:00
commit 2b80d75aa2
8 changed files with 82 additions and 79 deletions

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

@ -12,7 +12,7 @@
# included from sem.nim # included from sem.nim
# special marker values that indicates that we are # 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) # generation (needed for recursive types)
# 2) DestructorIsTrivial: completed the analysis before and determined # 2) DestructorIsTrivial: completed the analysis before and determined
# that the type has a trivial destructor # that the type has a trivial destructor
@ -41,7 +41,7 @@ proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
if t.kind != tyGenericBody: if t.kind != tyGenericBody:
localError(n.info, errDestructorNotGenericEnough) localError(n.info, errDestructorNotGenericEnough)
return return
t.destructor = s t.destructor = s
# automatically insert calls to base classes' destructors # automatically insert calls to base classes' destructors
if n.sons[bodyPos].kind != nkEmpty: 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]])) 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
result.addSon(caseBranch) result.addSon(caseBranch)
# maybe no fields were destroyed? # maybe no fields were destroyed?
if nonTrivialFields == 0: if nonTrivialFields == 0:
result = nil result = nil
@ -107,7 +108,7 @@ proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode =
proc generateDestructor(c: PContext, t: PType): PNode = proc generateDestructor(c: PContext, t: PType): PNode =
## generate a destructor for a user-defined object or tuple type ## generate a destructor for a user-defined object or tuple type
## returns nil if the destructor turns out to be trivial ## returns nil if the destructor turns out to be trivial
# XXX: This may be true for some C-imported types such as # XXX: This may be true for some C-imported types such as
# Tposix_spawnattr # Tposix_spawnattr
if t.n == nil or t.n.sons == nil: return 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 = proc instantiateDestructor(c: PContext, typ: PType): PType =
# returns nil if a variable of type `typ` doesn't require a # 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. # destructor that must be used for the varialbe.
# The destructor is either user-defined or automatically # The destructor is either user-defined or automatically
# generated by the compiler in a member-wise fashion. # generated by the compiler in a member-wise fashion.
var t = skipTypes(typ, {tyConst, tyMutable}).skipGenericAlias var t = skipTypes(typ, {tyConst, tyMutable}).skipGenericAlias
let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base else: t let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base else: t
if typeHoldingUserDefinition.destructor != nil: if typeHoldingUserDefinition.destructor != nil:
# XXX: This is not entirely correct for recursive types, but we need # XXX: This is not entirely correct for recursive types, but we need
# it temporarily to hide the "destroy is already defined" problem # it temporarily to hide the "destroy is already defined" problem
@ -135,7 +136,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
return typeHoldingUserDefinition return typeHoldingUserDefinition
else: else:
return nil return nil
t = t.skipTypes({tyGenericInst}) t = t.skipTypes({tyGenericInst})
case t.kind case t.kind
of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs: of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
@ -200,16 +201,16 @@ proc insertDestructors(c: PContext,
varId = varSection[j][0] varId = varSection[j][0]
varTyp = varId.sym.typ varTyp = varId.sym.typ
info = varId.info info = varId.info
if varTyp == nil or sfGlobal in varId.sym.flags: continue if varTyp == nil or sfGlobal in varId.sym.flags: continue
let destructableT = instantiateDestructor(c, varTyp) let destructableT = instantiateDestructor(c, varTyp)
if destructableT != nil: if destructableT != nil:
var tryStmt = newNodeI(nkTryStmt, info) var tryStmt = newNodeI(nkTryStmt, info)
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)
@ -221,7 +222,7 @@ proc insertDestructors(c: PContext,
else: else:
result.inner = newNodeI(nkStmtList, info) result.inner = newNodeI(nkStmtList, info)
tryStmt.addSon(result.inner) tryStmt.addSon(result.inner)
tryStmt.addSon( tryStmt.addSon(
newNode(nkFinally, info, @[ newNode(nkFinally, info, @[
semStmt(c, newNode(nkCall, info, @[ semStmt(c, newNode(nkCall, info, @[

View file

@ -167,10 +167,10 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result.typ = n[1].typ result.typ = n[1].typ
of mDotDot: of mDotDot:
result = n result = n
# we only need to warnings here about negative indexing: # disallow negative indexing for now:
if isNegative(n.sons[1]) or (n.len > 2 and isNegative(n.sons[2])): if not c.p.bracketExpr.isNil:
message(n.info, warnDeprecated, if isNegative(n.sons[1]) or (n.len > 2 and isNegative(n.sons[2])):
"use '^' instead of '-'; negative indexing") localError(n.info, "use '^' instead of '-'; negative indexing is obsolete")
of mRoof: of mRoof:
# error correction: # error correction:
result = n.sons[1] result = n.sons[1]

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

@ -18,8 +18,8 @@ import sockets, os
## This module implements an asynchronous event loop together with asynchronous ## This module implements an asynchronous event loop together with asynchronous
## sockets which use this event loop. ## sockets which use this event loop.
## It is akin to Python's asyncore module. Many modules that use sockets ## 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 ## 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 ## ``register`` function which you should use to add the desired objects to a
## dispatcher which you created so ## dispatcher which you created so
## that you can receive the events associated with that module's object. ## that you can receive the events associated with that module's object.
## ##
@ -27,19 +27,19 @@ import sockets, os
## function in a while loop. ## function in a while loop.
## ##
## **Note:** Most modules have tasks which need to be ran regularly, this is ## **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. ## very long one. In most cases the default timeout is fine.
## ##
## **Note:** This module currently only supports select(), this is limited by ## **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 ## FD_SETSIZE, which is usually 1024. So you may only be able to use 1024
## sockets at a time. ## sockets at a time.
## ##
## Most (if not all) modules that use asyncio provide a userArg which is passed ## 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 ## on with the events. The type that you set userArg to must be inheriting from
## ``RootObj``! ## ``RootObj``!
## ##
## **Note:** If you want to provide async ability to your module please do not ## **Note:** If you want to provide async ability to your module please do not
## use the ``Delegate`` object, instead use ``AsyncSocket``. It is possible ## use the ``Delegate`` object, instead use ``AsyncSocket``. It is possible
## that in the future this type's fields will not be exported therefore breaking ## that in the future this type's fields will not be exported therefore breaking
## your code. ## your code.
## ##
@ -59,11 +59,11 @@ import sockets, os
## socket which will give you the client which is connecting. You should then ## 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 ## set any events that you want to use on that client and add it to your dispatcher
## using the ``register`` procedure. ## using the ``register`` procedure.
## ##
## An example ``handleAccept`` follows: ## An example ``handleAccept`` follows:
## ##
## .. code-block:: nim ## .. code-block:: nim
## ##
## var disp = newDispatcher() ## var disp = newDispatcher()
## ... ## ...
## proc handleAccept(s: AsyncSocket) = ## proc handleAccept(s: AsyncSocket) =
@ -74,7 +74,7 @@ import sockets, os
## client.handleRead = ... ## client.handleRead = ...
## disp.register(client) ## disp.register(client)
## ... ## ...
## ##
## For client sockets you should only be interested in the ``handleRead`` and ## For client sockets you should only be interested in the ``handleRead`` and
## ``handleConnect`` events. The former gets called whenever the socket has ## ``handleConnect`` events. The former gets called whenever the socket has
## received messages and can be read from and the latter gets called whenever ## 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 ## Getting a blocking client from an AsyncSocket
## ============================================= ## =============================================
## ##
## If you need a asynchronous server socket but you wish to process the clients ## If you need a asynchronous server socket but you wish to process the clients
## synchronously then you can use the ``getSocket`` converter to get ## synchronously then you can use the ``getSocket`` converter to get
## a ``Socket`` from the ``AsyncSocket`` object, this can then be combined ## a ``Socket`` from the ``AsyncSocket`` object, this can then be combined
## with ``accept`` like so: ## with ``accept`` like so:
## ##
## .. code-block:: nim ## .. code-block:: nim
## ##
## proc handleAccept(s: AsyncSocket) = ## proc handleAccept(s: AsyncSocket) =
## var client: Socket ## var client: Socket
## getSocket(s).accept(client) ## getSocket(s).accept(client)
@ -113,11 +113,11 @@ type
handleWrite*: proc (h: RootRef) {.nimcall, gcsafe.} handleWrite*: proc (h: RootRef) {.nimcall, gcsafe.}
handleError*: proc (h: RootRef) {.nimcall, gcsafe.} handleError*: proc (h: RootRef) {.nimcall, gcsafe.}
hasDataBuffered*: proc (h: RootRef): bool {.nimcall, gcsafe.} hasDataBuffered*: proc (h: RootRef): bool {.nimcall, gcsafe.}
open*: bool open*: bool
task*: proc (h: RootRef) {.nimcall, gcsafe.} task*: proc (h: RootRef) {.nimcall, gcsafe.}
mode*: FileMode mode*: FileMode
Delegate* = ref DelegateObj Delegate* = ref DelegateObj
Dispatcher* = ref DispatcherObj Dispatcher* = ref DispatcherObj
@ -144,7 +144,7 @@ type
deleg: Delegate deleg: Delegate
SocketStatus* = enum SocketStatus* = enum
SockIdle, SockConnecting, SockConnected, SockListening, SockClosed, SockIdle, SockConnecting, SockConnected, SockListening, SockClosed,
SockUDPBound SockUDPBound
{.deprecated: [TDelegate: DelegateObj, PDelegate: Delegate, {.deprecated: [TDelegate: DelegateObj, PDelegate: Delegate,
@ -176,8 +176,8 @@ proc newAsyncSocket(): AsyncSocket =
result.lineBuffer = "".TaintedString result.lineBuffer = "".TaintedString
result.sendBuffer = "" result.sendBuffer = ""
proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
protocol: Protocol = IPPROTO_TCP, protocol: Protocol = IPPROTO_TCP,
buffered = true): AsyncSocket = buffered = true): AsyncSocket =
## Initialises an AsyncSocket object. If a socket cannot be initialised ## Initialises an AsyncSocket object. If a socket cannot be initialised
## EOS is raised. ## EOS is raised.
@ -236,7 +236,7 @@ proc asyncSockHandleWrite(h: RootRef) =
if AsyncSocket(h).socket.isSSL and not if AsyncSocket(h).socket.isSSL and not
AsyncSocket(h).socket.gotHandshake: AsyncSocket(h).socket.gotHandshake:
return return
if AsyncSocket(h).info == SockConnecting: if AsyncSocket(h).info == SockConnecting:
AsyncSocket(h).handleConnect(AsyncSocket(h)) AsyncSocket(h).handleConnect(AsyncSocket(h))
AsyncSocket(h).info = SockConnected AsyncSocket(h).info = SockConnected
@ -256,10 +256,10 @@ 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 = ""
if AsyncSocket(h).handleWrite != nil: if AsyncSocket(h).handleWrite != nil:
AsyncSocket(h).handleWrite(AsyncSocket(h)) AsyncSocket(h).handleWrite(AsyncSocket(h))
except OSError: except OSError:
@ -284,7 +284,7 @@ when defined(ssl):
else: else:
# handshake will set socket's ``sslNoHandshake`` field. # handshake will set socket's ``sslNoHandshake`` field.
discard AsyncSocket(h).socket.handshake() discard AsyncSocket(h).socket.handshake()
proc asyncSockTask(h: RootRef) = proc asyncSockTask(h: RootRef) =
when defined(ssl): when defined(ssl):
@ -377,9 +377,9 @@ proc acceptAddr*(server: AsyncSocket, client: var AsyncSocket,
if c == invalidSocket: raiseSocketError(server.socket) if c == invalidSocket: raiseSocketError(server.socket)
c.setBlocking(false) # TODO: Needs to be tested. c.setBlocking(false) # TODO: Needs to be tested.
# deleg.open is set in ``toDelegate``. # deleg.open is set in ``toDelegate``.
client.socket = c client.socket = c
client.lineBuffer = "".TaintedString client.lineBuffer = "".TaintedString
client.sendBuffer = "" client.sendBuffer = ""
@ -393,7 +393,7 @@ proc accept*(server: AsyncSocket, client: var AsyncSocket) =
proc acceptAddr*(server: AsyncSocket): tuple[sock: AsyncSocket, proc acceptAddr*(server: AsyncSocket): tuple[sock: AsyncSocket,
address: string] {.deprecated.} = address: string] {.deprecated.} =
## Equivalent to ``sockets.acceptAddr``. ## Equivalent to ``sockets.acceptAddr``.
## ##
## **Deprecated since version 0.9.0:** Please use the function above. ## **Deprecated since version 0.9.0:** Please use the function above.
var client = newAsyncSocket() var client = newAsyncSocket()
var address: string = "" var address: string = ""
@ -441,17 +441,17 @@ proc isConnected*(s: AsyncSocket): bool =
## Determines whether ``s`` is connected. ## Determines whether ``s`` is connected.
return s.info == SockConnected return s.info == SockConnected
proc isListening*(s: AsyncSocket): bool = 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 return s.info == SockListening
proc isConnecting*(s: AsyncSocket): bool = proc isConnecting*(s: AsyncSocket): bool =
## Determines whether ``s`` is connecting. ## Determines whether ``s`` is connecting.
return s.info == SockConnecting return s.info == SockConnecting
proc isClosed*(s: AsyncSocket): bool = proc isClosed*(s: AsyncSocket): bool =
## Determines whether ``s`` has been closed. ## Determines whether ``s`` has been closed.
return s.info == SockClosed return s.info == SockClosed
proc isSendDataBuffered*(s: AsyncSocket): bool = proc isSendDataBuffered*(s: AsyncSocket): bool =
## Determines whether ``s`` has data waiting to be sent, i.e. whether this ## 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 return s.sendBuffer.len != 0
proc setHandleWrite*(s: AsyncSocket, proc setHandleWrite*(s: AsyncSocket,
@ -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 =
@ -561,10 +561,10 @@ proc timeValFromMilliseconds(timeout = 500): Timeval =
proc createFdSet(fd: var TFdSet, s: seq[Delegate], m: var int) = proc createFdSet(fd: var TFdSet, s: seq[Delegate], m: var int) =
FD_ZERO(fd) FD_ZERO(fd)
for i in items(s): for i in items(s):
m = max(m, int(i.fd)) m = max(m, int(i.fd))
FD_SET(i.fd, fd) FD_SET(i.fd, fd)
proc pruneSocketSet(s: var seq[Delegate], fd: var TFdSet) = proc pruneSocketSet(s: var seq[Delegate], fd: var TFdSet) =
var i = 0 var i = 0
var L = s.len var L = s.len
@ -576,16 +576,16 @@ proc pruneSocketSet(s: var seq[Delegate], fd: var TFdSet) =
inc(i) inc(i)
setLen(s, L) setLen(s, L)
proc select(readfds, writefds, exceptfds: var seq[Delegate], proc select(readfds, writefds, exceptfds: var seq[Delegate],
timeout = 500): int = timeout = 500): int =
var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
var rd, wr, ex: TFdSet var rd, wr, ex: TFdSet
var m = 0 var m = 0
createFdSet(rd, readfds, m) createFdSet(rd, readfds, m)
createFdSet(wr, writefds, m) createFdSet(wr, writefds, m)
createFdSet(ex, exceptfds, m) createFdSet(ex, exceptfds, m)
if timeout != -1: if timeout != -1:
result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), addr(tv))) result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), addr(tv)))
else: 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`. ## This function checks for events on all the delegates in the `PDispatcher`.
## It then proceeds to call the correct event handler. ## 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 ## open, otherwise ``False``. File descriptors that have been
## closed are immediately removed from the dispatcher automatically. ## 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 readDg, writeDg, errorDg: seq[Delegate] = @[]
var len = d.delegates.len var len = d.delegates.len
var dc = 0 var dc = 0
while dc < len: while dc < len:
let deleg = d.delegates[dc] let deleg = d.delegates[dc]
if (deleg.mode != fmWrite or deleg.mode != fmAppend) and deleg.open: 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. # File/socket has been closed. Remove it from dispatcher.
d.delegates[dc] = d.delegates[len-1] d.delegates[dc] = d.delegates[len-1]
dec len dec len
d.delegates.setLen(len) d.delegates.setLen(len)
var hasDataBufferedCount = 0 var hasDataBufferedCount = 0
for d in d.delegates: for d in d.delegates:
if d.hasDataBuffered(d.deleVal): if d.hasDataBuffered(d.deleVal):
hasDataBufferedCount.inc() hasDataBufferedCount.inc()
d.handleRead(d.deleVal) d.handleRead(d.deleVal)
if hasDataBufferedCount > 0: return true if hasDataBufferedCount > 0: return true
if readDg.len() == 0 and writeDg.len() == 0: if readDg.len() == 0 and writeDg.len() == 0:
## TODO: Perhaps this shouldn't return if errorDg has something? ## TODO: Perhaps this shouldn't return if errorDg has something?
return false return false
if select(readDg, writeDg, errorDg, timeout) != 0: if select(readDg, writeDg, errorDg, timeout) != 0:
for i in 0..len(d.delegates)-1: for i in 0..len(d.delegates)-1:
if i > len(d.delegates)-1: break # One delegate might've been removed. 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) deleg.handleWrite(deleg.deleVal)
if deleg notin errorDg: if deleg notin errorDg:
deleg.handleError(deleg.deleVal) deleg.handleError(deleg.deleVal)
# Execute tasks # Execute tasks
for i in items(d.delegates): for i in items(d.delegates):
i.task(i.deleVal) i.task(i.deleVal)
@ -664,7 +664,7 @@ when isMainModule:
proc testConnect(s: AsyncSocket, no: int) = proc testConnect(s: AsyncSocket, no: int) =
echo("Connected! " & $no) echo("Connected! " & $no)
proc testRead(s: AsyncSocket, no: int) = proc testRead(s: AsyncSocket, no: int) =
echo("Reading! " & $no) echo("Reading! " & $no)
var data = "" var data = ""
@ -682,31 +682,31 @@ when isMainModule:
var address = "" var address = ""
s.acceptAddr(client, address) s.acceptAddr(client, address)
echo("Accepted ", address) echo("Accepted ", address)
client.handleRead = client.handleRead =
proc (s: AsyncSocket) = proc (s: AsyncSocket) =
testRead(s, 2) testRead(s, 2)
disp.register(client) disp.register(client)
proc main = proc main =
var d = newDispatcher() var d = newDispatcher()
var s = asyncSocket() var s = asyncSocket()
s.connect("amber.tenthbit.net", Port(6667)) s.connect("amber.tenthbit.net", Port(6667))
s.handleConnect = s.handleConnect =
proc (s: AsyncSocket) = proc (s: AsyncSocket) =
testConnect(s, 1) testConnect(s, 1)
s.handleRead = s.handleRead =
proc (s: AsyncSocket) = proc (s: AsyncSocket) =
testRead(s, 1) testRead(s, 1)
d.register(s) d.register(s)
var server = asyncSocket() var server = asyncSocket()
server.handleAccept = server.handleAccept =
proc (s: AsyncSocket) = proc (s: AsyncSocket) =
testAccept(s, d, 78) testAccept(s, d, 78)
server.bindAddr(Port(5555)) server.bindAddr(Port(5555))
server.listen() server.listen()
d.register(server) d.register(server)
while d.poll(-1): discard while d.poll(-1): discard
main() main()

View file

@ -2865,7 +2865,7 @@ 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. ## 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. If ## slice assignment for strings. If
@ -2876,8 +2876,8 @@ when hostOS != "standalone":
## 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:
@ -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] = proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] =
## slice operation for sequences. ## 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]
@ -2928,8 +2928,8 @@ proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) =
## slice assignment for sequences. 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:

View file

@ -59,11 +59,12 @@ News
echo x.T echo x.T
inc x inc x
- **Negative indexing for slicing is deprecated and will be removed in the - **Negative indexing for slicing does not work anymore!** Instead
next version of the language.** Instead of ``a[0.. -1]`` you can of ``a[0.. -1]`` you can
use ``a[0.. ^1]``. This also works with accessing a single use ``a[0.. ^1]``. This also works with accessing a single
element ``a[^1]``. Note that we cannot detect this reliably as it is element ``a[^1]``. Note that we cannot detect this reliably as it is
determined at **runtime** whether negative indexing is used! 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 - The compiler now warns about code like ``foo +=1`` which uses inconsistent
spacing around binary operators. Later versions of the language will parse spacing around binary operators. Later versions of the language will parse
these as unary operators instead so that ``echo $foo`` finally can do what these as unary operators instead so that ``echo $foo`` finally can do what