fixes #2420; negative indexing for slicing is obsolete (breaking change!)
This commit is contained in:
parent
46fb0e0bac
commit
2b80d75aa2
8 changed files with 82 additions and 79 deletions
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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, @[
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue