mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-05 11:24:08 +00:00
Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
@@ -585,8 +585,9 @@ proc StrTableContains(t: TStrTable, n: PSym): bool =
|
||||
proc StrTableRawInsert(data: var TSymSeq, n: PSym) =
|
||||
var h: THash = n.name.h and high(data)
|
||||
while data[h] != nil:
|
||||
if data[h] == n:
|
||||
InternalError(n.info, "StrTableRawInsert: " & n.name.s)
|
||||
if data[h] == n:
|
||||
# allowed for 'export' feature:
|
||||
#InternalError(n.info, "StrTableRawInsert: " & n.name.s)
|
||||
return
|
||||
h = nextTry(h, high(data))
|
||||
assert(data[h] == nil)
|
||||
@@ -617,23 +618,23 @@ proc StrTableAdd(t: var TStrTable, n: PSym) =
|
||||
StrTableRawInsert(t.data, n)
|
||||
inc(t.counter)
|
||||
|
||||
proc StrTableIncl*(t: var TStrTable, n: PSym): bool =
|
||||
proc StrTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
|
||||
# returns true if n is already in the string table:
|
||||
# It is essential that `n` is written nevertheless!
|
||||
# This way the newest redefinition is picked by the semantic analyses!
|
||||
assert n.name != nil
|
||||
var h: THash = n.name.h and high(t.data)
|
||||
while true:
|
||||
while true:
|
||||
var it = t.data[h]
|
||||
if it == nil: break
|
||||
if it.name.id == n.name.id:
|
||||
if it == nil: break
|
||||
if it.name.id == n.name.id:
|
||||
t.data[h] = n # overwrite it with newer definition!
|
||||
return true # found it
|
||||
h = nextTry(h, high(t.data))
|
||||
if mustRehash(len(t.data), t.counter):
|
||||
if mustRehash(len(t.data), t.counter):
|
||||
StrTableEnlarge(t)
|
||||
StrTableRawInsert(t.data, n)
|
||||
else:
|
||||
else:
|
||||
assert(t.data[h] == nil)
|
||||
t.data[h] = n
|
||||
inc(t.counter)
|
||||
|
||||
@@ -15,7 +15,6 @@ import
|
||||
|
||||
proc evalImport*(c: PContext, n: PNode): PNode
|
||||
proc evalFrom*(c: PContext, n: PNode): PNode
|
||||
proc importAllSymbols*(c: PContext, fromMod: PSym)
|
||||
|
||||
proc getModuleName*(n: PNode): string =
|
||||
# This returns a short relative module name without the nim extension
|
||||
@@ -29,9 +28,11 @@ proc getModuleName*(n: PNode): string =
|
||||
of nkSym:
|
||||
result = n.sym.name.s
|
||||
else:
|
||||
localError(n.info, errGenerated,
|
||||
"invalide module name: '$1'" % renderTree(n))
|
||||
result = ""
|
||||
# hacky way to implement 'x / y /../ z':
|
||||
result = renderTree(n, {renderNoComments}).replace(" ")
|
||||
#localError(n.info, errGenerated,
|
||||
# "invalide module name: '$1'" % renderTree(n))
|
||||
#result = ""
|
||||
|
||||
proc checkModuleName*(n: PNode): string =
|
||||
# This returns the full canonical path for a given module import
|
||||
@@ -40,42 +41,43 @@ proc checkModuleName*(n: PNode): string =
|
||||
if result.len == 0:
|
||||
LocalError(n.info, errCannotOpenFile, modulename)
|
||||
|
||||
proc rawImportSymbol(c: PContext, s: PSym) =
|
||||
proc rawImportSymbol(c: PContext, s: PSym) =
|
||||
# This does not handle stubs, because otherwise loading on demand would be
|
||||
# pointless in practice. So importing stubs is fine here!
|
||||
var copy = s # do not copy symbols when importing!
|
||||
# check if we have already a symbol of the same name:
|
||||
var check = StrTableGet(c.tab.stack[importTablePos], s.name)
|
||||
if check != nil and check.id != copy.id:
|
||||
if s.kind notin OverloadableSyms:
|
||||
if check != nil and check.id != s.id:
|
||||
if s.kind notin OverloadableSyms:
|
||||
# s and check need to be qualified:
|
||||
Incl(c.AmbiguousSymbols, copy.id)
|
||||
Incl(c.AmbiguousSymbols, s.id)
|
||||
Incl(c.AmbiguousSymbols, check.id)
|
||||
StrTableAdd(c.tab.stack[importTablePos], copy)
|
||||
if s.kind == skType:
|
||||
# thanks to 'export' feature, it could be we import the same symbol from
|
||||
# multiple sources, so we need to call 'StrTableAdd' here:
|
||||
StrTableAdd(c.tab.stack[importTablePos], s)
|
||||
if s.kind == skType:
|
||||
var etyp = s.typ
|
||||
if etyp.kind in {tyBool, tyEnum} and sfPure notin s.flags:
|
||||
for j in countup(0, sonsLen(etyp.n) - 1):
|
||||
if etyp.kind in {tyBool, tyEnum} and sfPure notin s.flags:
|
||||
for j in countup(0, sonsLen(etyp.n) - 1):
|
||||
var e = etyp.n.sons[j].sym
|
||||
if (e.Kind != skEnumField):
|
||||
if e.Kind != skEnumField:
|
||||
InternalError(s.info, "rawImportSymbol")
|
||||
# BUGFIX: because of aliases for enums the symbol may already
|
||||
# have been put into the symbol table
|
||||
# BUGFIX: but only iff they are the same symbols!
|
||||
var it: TIdentIter
|
||||
check = InitIdentIter(it, c.tab.stack[importTablePos], e.name)
|
||||
while check != nil:
|
||||
if check.id == e.id:
|
||||
while check != nil:
|
||||
if check.id == e.id:
|
||||
e = nil
|
||||
break
|
||||
break
|
||||
check = NextIdentIter(it, c.tab.stack[importTablePos])
|
||||
if e != nil:
|
||||
if e != nil:
|
||||
rawImportSymbol(c, e)
|
||||
else:
|
||||
# rodgen assures that converters and patterns are no stubs
|
||||
if s.kind == skConverter: addConverter(c, s)
|
||||
if hasPattern(s): addPattern(c, s)
|
||||
|
||||
|
||||
proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
|
||||
let ident = lookups.considerAcc(n)
|
||||
let s = StrTableGet(fromMod.tab, ident)
|
||||
@@ -96,17 +98,6 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
|
||||
rawImportSymbol(c, e)
|
||||
e = NextIdentIter(it, fromMod.tab)
|
||||
else: rawImportSymbol(c, s)
|
||||
|
||||
proc importAllSymbols(c: PContext, fromMod: PSym) =
|
||||
var i: TTabIter
|
||||
var s = InitTabIter(i, fromMod.tab)
|
||||
while s != nil:
|
||||
if s.kind != skModule:
|
||||
if s.kind != skEnumField:
|
||||
if s.Kind notin ExportableSymKinds:
|
||||
InternalError(s.info, "importAllSymbols: " & $s.kind)
|
||||
rawImportSymbol(c, s) # this is correct!
|
||||
s = NextIter(i, fromMod.tab)
|
||||
|
||||
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
|
||||
var i: TTabIter
|
||||
@@ -116,12 +107,34 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
|
||||
if s.kind != skEnumField:
|
||||
if s.Kind notin ExportableSymKinds:
|
||||
InternalError(s.info, "importAllSymbols: " & $s.kind)
|
||||
if s.name.id notin exceptSet:
|
||||
if exceptSet.empty or s.name.id notin exceptSet:
|
||||
rawImportSymbol(c, s)
|
||||
s = NextIter(i, fromMod.tab)
|
||||
|
||||
proc importAllSymbols*(c: PContext, fromMod: PSym) =
|
||||
var exceptSet: TIntSet
|
||||
importAllSymbolsExcept(c, fromMod, exceptSet)
|
||||
|
||||
proc importForwarded(c: PContext, n: PNode, exceptSet: TIntSet) =
|
||||
if n.isNil: return
|
||||
case n.kind
|
||||
of nkExportStmt:
|
||||
for a in n:
|
||||
assert a.kind == nkSym
|
||||
let s = a.sym
|
||||
if s.kind == skModule:
|
||||
importAllSymbolsExcept(c, s, exceptSet)
|
||||
elif exceptSet.empty or s.name.id notin exceptSet:
|
||||
rawImportSymbol(c, s)
|
||||
of nkExportExceptStmt:
|
||||
localError(n.info, errGenerated, "'export except' not implemented")
|
||||
else:
|
||||
for i in 0 ..safeLen(n)-1:
|
||||
importForwarded(c, n.sons[i], exceptSet)
|
||||
|
||||
proc evalImport(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
var emptySet: TIntSet
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var f = checkModuleName(n.sons[i])
|
||||
if f.len > 0:
|
||||
@@ -130,7 +143,8 @@ proc evalImport(c: PContext, n: PNode): PNode =
|
||||
Message(n.sons[i].info, warnDeprecated, m.name.s)
|
||||
# ``addDecl`` needs to be done before ``importAllSymbols``!
|
||||
addDecl(c, m) # add symbol to symbol table of module
|
||||
importAllSymbols(c, m)
|
||||
importAllSymbolsExcept(c, m, emptySet)
|
||||
importForwarded(c, m.ast, emptySet)
|
||||
|
||||
proc evalFrom(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
@@ -155,3 +169,4 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode =
|
||||
let ident = lookups.considerAcc(n.sons[i])
|
||||
exceptSet.incl(ident.id)
|
||||
importAllSymbolsExcept(c, m, exceptSet)
|
||||
importForwarded(c, m.ast, exceptSet)
|
||||
|
||||
@@ -1659,6 +1659,26 @@ proc fixImmediateParams(n: PNode): PNode =
|
||||
|
||||
result = n
|
||||
|
||||
proc semExport(c: PContext, n: PNode): PNode =
|
||||
var x = newNodeI(n.kind, n.info)
|
||||
#let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len
|
||||
for i in 0.. <n.len:
|
||||
let a = n.sons[i]
|
||||
var o: TOverloadIter
|
||||
var s = initOverloadIter(o, c, a)
|
||||
if s == nil:
|
||||
localError(a.info, errGenerated, "invalid expr for 'export': " &
|
||||
renderTree(a))
|
||||
while s != nil:
|
||||
if s.kind in ExportableSymKinds+{skModule}:
|
||||
x.add(newSymNode(s, a.info))
|
||||
s = nextOverloadIter(o, c, a)
|
||||
if c.module.ast.isNil:
|
||||
c.module.ast = newNodeI(nkStmtList, n.info)
|
||||
assert c.module.ast.kind == nkStmtList
|
||||
c.module.ast.add x
|
||||
result = n
|
||||
|
||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
result = n
|
||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||
@@ -1861,6 +1881,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
of nkIncludeStmt:
|
||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "include")
|
||||
result = evalInclude(c, n)
|
||||
of nkExportStmt, nkExportExceptStmt:
|
||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "export")
|
||||
result = semExport(c, n)
|
||||
of nkPragmaBlock:
|
||||
result = semPragmaBlock(c, n)
|
||||
of nkStaticStmt:
|
||||
|
||||
@@ -3656,7 +3656,7 @@ don't need to instantiate the code multiple times, because types then can be
|
||||
manipulated using the unified internal symbol representation. In such context
|
||||
typedesc acts as any other type. You can create variables, store typedesc
|
||||
values inside containers and so on. For example, here is how we can create
|
||||
a type-safe wrapper for the unsafe `printf` function form C:
|
||||
a type-safe wrapper for the unsafe `printf` function from C:
|
||||
|
||||
.. code-block:: nimrod
|
||||
macro safePrintF(formatString: string{lit}, args: vararg[expr]): expr =
|
||||
@@ -3744,7 +3744,7 @@ This is best illustrated by an example:
|
||||
Import statement
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
After the import statement a list of module names can follow or a single
|
||||
After the `import`:idx: statement a list of module names can follow or a single
|
||||
module name followed by an ``except`` to prevent some symbols to be imported:
|
||||
|
||||
.. code-block:: nimrod
|
||||
@@ -3754,6 +3754,33 @@ module name followed by an ``except`` to prevent some symbols to be imported:
|
||||
echo "$1" % "abc"
|
||||
|
||||
|
||||
Export statement
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
An `export`:idx: statement can be used for symbol fowarding so that client
|
||||
modules don't need to import a module's dependencies:
|
||||
|
||||
.. code-block:: nimrod
|
||||
# module B
|
||||
type TMyObject* = object
|
||||
|
||||
.. code-block:: nimrod
|
||||
# module A
|
||||
import B
|
||||
export B.TMyObject
|
||||
|
||||
proc `$`*(x: TMyObject): string = "my object"
|
||||
|
||||
|
||||
.. code-block:: nimrod
|
||||
# module C
|
||||
import A
|
||||
|
||||
# B.TMyObject has been imported implicitly here:
|
||||
var x: TMyObject
|
||||
echo($x)
|
||||
|
||||
|
||||
Scope rules
|
||||
-----------
|
||||
Identifiers are valid from the point of their declaration until the end of
|
||||
|
||||
@@ -35,6 +35,9 @@ import sockets, os
|
||||
## that in the future this type's fields will not be exported therefore breaking
|
||||
## your code.
|
||||
##
|
||||
## **Warning:** The API of this module is unstable, and therefore is subject
|
||||
## to change.
|
||||
##
|
||||
## Asynchronous sockets
|
||||
## ====================
|
||||
##
|
||||
|
||||
@@ -190,6 +190,11 @@ proc `$`*(s: TIntSet): string =
|
||||
## The `$` operator for int sets.
|
||||
dollarImpl()
|
||||
|
||||
proc empty*(s: TIntSet): bool {.inline.} =
|
||||
## returns true if `s` is empty. This is safe to call even before
|
||||
## the set has been initialized with `initIntSet`.
|
||||
result = s.counter == 0
|
||||
|
||||
when isMainModule:
|
||||
var x = initIntSet()
|
||||
x.incl(1)
|
||||
|
||||
@@ -26,6 +26,10 @@ import sockets, strutils, parseutils, times, os, asyncio
|
||||
## var ftp = FTPClient("example.org", user = "user", pass = "pass")
|
||||
## ftp.connect()
|
||||
## ftp.retrFile("file.ext", "file.ext")
|
||||
##
|
||||
## **Warning:** The API of this module is unstable, and therefore is subject
|
||||
## to change.
|
||||
|
||||
|
||||
type
|
||||
TFTPClient* = object of TObject
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
##
|
||||
## run(handleRequest, TPort(80))
|
||||
##
|
||||
## **Warning:** The API of this module is unstable, and therefore is subject
|
||||
## to change.
|
||||
|
||||
import parseutils, strutils, os, osproc, strtabs, streams, sockets, asyncio
|
||||
|
||||
|
||||
185
lib/pure/irc.nim
185
lib/pure/irc.nim
@@ -16,15 +16,21 @@
|
||||
## the amount of lag.
|
||||
##
|
||||
## .. code-block:: Nimrod
|
||||
## var client = irc("irc.server.net", joinChans = @["#channel"])
|
||||
##
|
||||
## var client = irc("picheta.me", joinChans = @["#bots"])
|
||||
## client.connect()
|
||||
## while True:
|
||||
## var event: TIRCEvent
|
||||
## if client.poll(event):
|
||||
## case event.typ
|
||||
## of EvDisconnected: break
|
||||
## of EvConnected: nil
|
||||
## of EvDisconnected:
|
||||
## client.reconnect()
|
||||
## of EvMsg:
|
||||
## # Where all the magic happens.
|
||||
## # Write your message reading code here.
|
||||
##
|
||||
## **Warning:** The API of this module is unstable, and therefore is subject
|
||||
## to change.
|
||||
|
||||
import sockets, strutils, parseutils, times, asyncio
|
||||
|
||||
@@ -34,11 +40,15 @@ type
|
||||
port: TPort
|
||||
nick, user, realname, serverPass: string
|
||||
case isAsync: bool
|
||||
of false:
|
||||
sock: TSocket
|
||||
of true:
|
||||
handleEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent) {.closure.}
|
||||
handleEvent: proc (irc: PAsyncIRC, ev: TIRCEvent) {.closure.}
|
||||
asyncSock: PAsyncSocket
|
||||
myDispatcher: PDispatcher
|
||||
of false:
|
||||
dummyA: pointer
|
||||
dummyB: pointer # workaround a Nimrod API issue
|
||||
dummyC: pointer
|
||||
sock: TSocket
|
||||
status: TInfo
|
||||
lastPing: float
|
||||
lastPong: float
|
||||
@@ -47,6 +57,8 @@ type
|
||||
msgLimit: bool
|
||||
messageBuffer: seq[tuple[timeToSend: float, m: string]]
|
||||
|
||||
PIRC* = ref TIRC
|
||||
|
||||
PAsyncIRC* = ref TAsyncIRC
|
||||
TAsyncIRC* = object of TIRC
|
||||
|
||||
@@ -68,9 +80,13 @@ type
|
||||
MError
|
||||
|
||||
TIRCEventType* = enum
|
||||
EvMsg, EvDisconnected
|
||||
EvMsg, EvConnected, EvDisconnected
|
||||
TIRCEvent* = object ## IRC Event
|
||||
case typ*: TIRCEventType
|
||||
of EvConnected:
|
||||
## Connected to server.
|
||||
## Only occurs with AsyncIRC.
|
||||
nil
|
||||
of EvDisconnected:
|
||||
## Disconnected from the server
|
||||
nil
|
||||
@@ -82,7 +98,7 @@ type
|
||||
origin*: string ## The channel/user that this msg originated from
|
||||
raw*: string ## Raw IRC message
|
||||
|
||||
proc send*(irc: var TIRC, message: string, sendImmediately = false) =
|
||||
proc send*(irc: PIRC, message: string, sendImmediately = false) =
|
||||
## Sends ``message`` as a raw command. It adds ``\c\L`` for you.
|
||||
var sendMsg = true
|
||||
if irc.msgLimit and not sendImmediately:
|
||||
@@ -104,15 +120,15 @@ proc send*(irc: var TIRC, message: string, sendImmediately = false) =
|
||||
# but I can't exactly check for EBrokenPipe.
|
||||
irc.status = SockClosed
|
||||
|
||||
proc privmsg*(irc: var TIRC, target, message: string) =
|
||||
proc privmsg*(irc: PIRC, target, message: string) =
|
||||
## Sends ``message`` to ``target``. ``Target`` can be a channel, or a user.
|
||||
irc.send("PRIVMSG $1 :$2" % [target, message])
|
||||
|
||||
proc notice*(irc: var TIRC, target, message: string) =
|
||||
proc notice*(irc: PIRC, target, message: string) =
|
||||
## Sends ``notice`` to ``target``. ``Target`` can be a channel, or a user.
|
||||
irc.send("NOTICE $1 :$2" % [target, message])
|
||||
|
||||
proc join*(irc: var TIRC, channel: string, key = "") =
|
||||
proc join*(irc: PIRC, channel: string, key = "") =
|
||||
## Joins ``channel``.
|
||||
##
|
||||
## If key is not ``""``, then channel is assumed to be key protected and this
|
||||
@@ -122,16 +138,19 @@ proc join*(irc: var TIRC, channel: string, key = "") =
|
||||
else:
|
||||
irc.send("JOIN " & channel & " " & key)
|
||||
|
||||
proc part*(irc: var TIRC, channel, message: string) =
|
||||
proc part*(irc: PIRC, channel, message: string) =
|
||||
## Leaves ``channel`` with ``message``.
|
||||
irc.send("PART " & channel & " :" & message)
|
||||
|
||||
proc close*(irc: var TIRC) =
|
||||
proc close*(irc: PIRC) =
|
||||
## Closes connection to an IRC server.
|
||||
##
|
||||
## **Warning:** This procedure does not send a ``QUIT`` message to the server.
|
||||
irc.status = SockClosed
|
||||
irc.sock.close()
|
||||
if irc.isAsync:
|
||||
irc.asyncSock.close()
|
||||
else:
|
||||
irc.sock.close()
|
||||
|
||||
proc isNumber(s: string): bool =
|
||||
## Checks if `s` contains only numbers.
|
||||
@@ -202,12 +221,11 @@ proc parseMessage(msg: string): TIRCEvent =
|
||||
inc(i) # Skip `:`.
|
||||
result.params.add(msg[i..msg.len-1])
|
||||
|
||||
proc connect*(irc: var TIRC) =
|
||||
proc connect*(irc: PIRC) =
|
||||
## Connects to an IRC server as specified by ``irc``.
|
||||
assert(irc.address != "")
|
||||
assert(irc.port != TPort(0))
|
||||
|
||||
irc.sock = socket()
|
||||
irc.sock.connect(irc.address, irc.port)
|
||||
|
||||
irc.status = SockConnected
|
||||
@@ -217,13 +235,21 @@ proc connect*(irc: var TIRC) =
|
||||
irc.send("NICK " & irc.nick, true)
|
||||
irc.send("USER $1 * 0 :$2" % [irc.user, irc.realname], true)
|
||||
|
||||
proc reconnect*(irc: PIRC) =
|
||||
## Reconnects to an IRC server.
|
||||
##
|
||||
## This should be used when an ``EvDisconnected`` event occurs.
|
||||
irc.sock = socket()
|
||||
irc.connect()
|
||||
|
||||
proc irc*(address: string, port: TPort = 6667.TPort,
|
||||
nick = "NimrodBot",
|
||||
user = "NimrodBot",
|
||||
realname = "NimrodBot", serverPass = "",
|
||||
joinChans: seq[string] = @[],
|
||||
msgLimit: bool = true): TIRC =
|
||||
msgLimit: bool = true): PIRC =
|
||||
## Creates a ``TIRC`` object.
|
||||
new(result)
|
||||
result.address = address
|
||||
result.port = port
|
||||
result.nick = nick
|
||||
@@ -237,8 +263,9 @@ proc irc*(address: string, port: TPort = 6667.TPort,
|
||||
result.msgLimit = msgLimit
|
||||
result.messageBuffer = @[]
|
||||
result.status = SockIdle
|
||||
result.sock = socket()
|
||||
|
||||
proc processLine(irc: var TIRC, line: string): TIRCEvent =
|
||||
proc processLine(irc: PIRC, line: string): TIRCEvent =
|
||||
if line.len == 0:
|
||||
irc.close()
|
||||
result.typ = EvDisconnected
|
||||
@@ -271,7 +298,7 @@ proc processLine(irc: var TIRC, line: string): TIRCEvent =
|
||||
if result.nick == irc.nick:
|
||||
irc.nick = result.params[0]
|
||||
|
||||
proc processOther(irc: var TIRC, ev: var TIRCEvent): bool =
|
||||
proc processOther(irc: PIRC, ev: var TIRCEvent): bool =
|
||||
result = false
|
||||
if epochTime() - irc.lastPing >= 20.0:
|
||||
irc.lastPing = epochTime()
|
||||
@@ -290,7 +317,7 @@ proc processOther(irc: var TIRC, ev: var TIRCEvent): bool =
|
||||
break # messageBuffer is guaranteed to be from the quickest to the
|
||||
# later-est.
|
||||
|
||||
proc poll*(irc: var TIRC, ev: var TIRCEvent,
|
||||
proc poll*(irc: PIRC, ev: var TIRCEvent,
|
||||
timeout: int = 500): bool =
|
||||
## This function parses a single message from the IRC server and returns
|
||||
## a TIRCEvent.
|
||||
@@ -316,46 +343,32 @@ proc poll*(irc: var TIRC, ev: var TIRCEvent,
|
||||
|
||||
if processOther(irc, ev): result = true
|
||||
|
||||
proc getLag*(irc: var TIRC): float =
|
||||
proc getLag*(irc: PIRC): float =
|
||||
## Returns the latency between this client and the IRC server in seconds.
|
||||
##
|
||||
## If latency is unknown, returns -1.0.
|
||||
return irc.lag
|
||||
|
||||
proc isConnected*(irc: var TIRC): bool =
|
||||
proc isConnected*(irc: PIRC): bool =
|
||||
## Returns whether this IRC client is connected to an IRC server.
|
||||
return irc.status == SockConnected
|
||||
|
||||
proc getNick*(irc: var TIRC): string =
|
||||
proc getNick*(irc: PIRC): string =
|
||||
## Returns the current nickname of the client.
|
||||
return irc.nick
|
||||
|
||||
# -- Asyncio dispatcher
|
||||
|
||||
proc connect*(irc: PAsyncIRC) =
|
||||
## Equivalent of connect for ``TIRC`` but specifically created for asyncio.
|
||||
assert(irc.address != "")
|
||||
assert(irc.port != TPort(0))
|
||||
|
||||
irc.asyncSock = AsyncSocket()
|
||||
irc.asyncSock.connect(irc.address, irc.port)
|
||||
|
||||
proc handleConnect(s: PAsyncSocket, irc: PAsyncIRC) =
|
||||
# Greet the server :)
|
||||
if irc.serverPass != "": irc[].send("PASS " & irc.serverPass, true)
|
||||
irc[].send("NICK " & irc.nick, true)
|
||||
irc[].send("USER $1 * 0 :$2" % [irc.user, irc.realname], true)
|
||||
|
||||
discard """proc handleConnect(h: PObject) =
|
||||
var irc = PAsyncIRC(h)
|
||||
|
||||
# Greet the server :)
|
||||
if irc.serverPass != "": irc[].send("PASS " & irc.serverPass, true)
|
||||
irc[].send("NICK " & irc.nick, true)
|
||||
irc[].send("USER $1 * 0 :$2" % [irc.user, irc.realname], true)
|
||||
|
||||
if irc.serverPass != "": irc.send("PASS " & irc.serverPass, true)
|
||||
irc.send("NICK " & irc.nick, true)
|
||||
irc.send("USER $1 * 0 :$2" % [irc.user, irc.realname], true)
|
||||
irc.status = SockConnected
|
||||
"""
|
||||
|
||||
var ev: TIRCEvent
|
||||
ev.typ = EvConnected
|
||||
irc.handleEvent(irc, ev)
|
||||
|
||||
proc handleRead(s: PAsyncSocket, irc: PAsyncIRC) =
|
||||
var line = "".TaintedString
|
||||
@@ -363,42 +376,48 @@ proc handleRead(s: PAsyncSocket, irc: PAsyncIRC) =
|
||||
if ret:
|
||||
if line == "":
|
||||
var ev: TIRCEvent
|
||||
irc[].close()
|
||||
irc.close()
|
||||
ev.typ = EvDisconnected
|
||||
irc[].handleEvent(irc[], ev)
|
||||
irc.handleEvent(irc, ev)
|
||||
else:
|
||||
var ev = irc[].processLine(line.string)
|
||||
irc[].handleEvent(irc[], ev)
|
||||
|
||||
discard """proc handleRead(h: PObject) =
|
||||
var irc = PAsyncIRC(h)
|
||||
var line = "".TaintedString
|
||||
var ret = irc.sock.recvLineAsync(line)
|
||||
case ret
|
||||
of RecvFullLine:
|
||||
var ev = irc[].processLine(irc.lineBuffer.string & line.string)
|
||||
irc.handleEvent(irc[], ev, irc.userArg)
|
||||
irc.lineBuffer = "".TaintedString
|
||||
of RecvPartialLine:
|
||||
if line.string != "":
|
||||
string(irc.lineBuffer).add(line.string)
|
||||
of RecvDisconnected:
|
||||
var ev: TIRCEvent
|
||||
irc[].close()
|
||||
ev.typ = EvDisconnected
|
||||
irc.handleEvent(irc[], ev, irc.userArg)
|
||||
of RecvFail: nil"""
|
||||
var ev = irc.processLine(line.string)
|
||||
irc.handleEvent(irc, ev)
|
||||
|
||||
proc handleTask(s: PAsyncSocket, irc: PAsyncIRC) =
|
||||
var ev: TIRCEvent
|
||||
if irc[].processOther(ev):
|
||||
irc.handleEvent(irc[], ev)
|
||||
if irc.processOther(ev):
|
||||
irc.handleEvent(irc, ev)
|
||||
|
||||
proc register*(d: PDispatcher, irc: PAsyncIRC) =
|
||||
## Registers ``irc`` with dispatcher ``d``.
|
||||
irc.asyncSock.handleConnect =
|
||||
proc (s: PAsyncSocket) =
|
||||
handleConnect(s, irc)
|
||||
irc.asyncSock.handleRead =
|
||||
proc (s: PAsyncSocket) =
|
||||
handleRead(s, irc)
|
||||
irc.asyncSock.handleTask =
|
||||
proc (s: PAsyncSocket) =
|
||||
handleTask(s, irc)
|
||||
d.register(irc.asyncSock)
|
||||
irc.myDispatcher = d
|
||||
|
||||
proc connect*(irc: PAsyncIRC) =
|
||||
## Equivalent of connect for ``TIRC`` but specifically created for asyncio.
|
||||
assert(irc.address != "")
|
||||
assert(irc.port != TPort(0))
|
||||
|
||||
discard """proc handleTask(h: PObject) =
|
||||
var irc = PAsyncIRC(h)
|
||||
var ev: TIRCEvent
|
||||
if PAsyncIRC(h)[].processOther(ev):
|
||||
irc.handleEvent(irc[], ev, irc.userArg)"""
|
||||
irc.asyncSock.connect(irc.address, irc.port)
|
||||
|
||||
proc reconnect*(irc: PAsyncIRC) =
|
||||
## Reconnects to an IRC server.
|
||||
##
|
||||
## This should be used when an ``EvDisconnected`` event occurs.
|
||||
##
|
||||
## When successfully reconnected an ``EvConnected`` event will occur.
|
||||
irc.asyncSock = AsyncSocket()
|
||||
irc.myDispatcher.register(irc)
|
||||
irc.connect()
|
||||
|
||||
proc asyncIRC*(address: string, port: TPort = 6667.TPort,
|
||||
nick = "NimrodBot",
|
||||
@@ -406,7 +425,7 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort,
|
||||
realname = "NimrodBot", serverPass = "",
|
||||
joinChans: seq[string] = @[],
|
||||
msgLimit: bool = true,
|
||||
ircEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent) {.closure.}
|
||||
ircEvent: proc (irc: PAsyncIRC, ev: TIRCEvent) {.closure.}
|
||||
): PAsyncIRC =
|
||||
## Use this function if you want to use asyncio's dispatcher.
|
||||
##
|
||||
@@ -429,19 +448,7 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort,
|
||||
result.msgLimit = msgLimit
|
||||
result.messageBuffer = @[]
|
||||
result.handleEvent = ircEvent
|
||||
|
||||
proc register*(d: PDispatcher, irc: PAsyncIRC) =
|
||||
## Registers ``irc`` with dispatcher ``d``.
|
||||
irc.asyncSock.handleConnect =
|
||||
proc (s: PAsyncSocket) =
|
||||
handleConnect(s, irc)
|
||||
irc.asyncSock.handleRead =
|
||||
proc (s: PAsyncSocket) =
|
||||
handleRead(s, irc)
|
||||
irc.asyncSock.handleTask =
|
||||
proc (s: PAsyncSocket) =
|
||||
handleTask(s, irc)
|
||||
d.register(irc.asyncSock)
|
||||
result.asyncSock = AsyncSocket()
|
||||
|
||||
when isMainModule:
|
||||
#var m = parseMessage("ERROR :Closing Link: dom96.co.cc (Ping timeout: 252 seconds)")
|
||||
@@ -456,6 +463,8 @@ when isMainModule:
|
||||
var event: TIRCEvent
|
||||
if client.poll(event):
|
||||
case event.typ
|
||||
of EvConnected:
|
||||
nil
|
||||
of EvDisconnected:
|
||||
break
|
||||
of EvMsg:
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
##
|
||||
## run(handleRequest)
|
||||
##
|
||||
## **Warning:** The API of this module is unstable, and therefore is subject
|
||||
## to change.
|
||||
|
||||
import sockets, strutils, os, strtabs, asyncio
|
||||
|
||||
|
||||
8
tests/compile/mexporta.nim
Normal file
8
tests/compile/mexporta.nim
Normal file
@@ -0,0 +1,8 @@
|
||||
# module A
|
||||
import mexportb
|
||||
export mexportb.TMyObject, mexportb.xyz
|
||||
|
||||
export mexportb.q
|
||||
|
||||
proc `$`*(x: TMyObject): string = "my object"
|
||||
|
||||
7
tests/compile/mexportb.nim
Normal file
7
tests/compile/mexportb.nim
Normal file
@@ -0,0 +1,7 @@
|
||||
# module B
|
||||
type TMyObject* = object
|
||||
|
||||
const xyz* = 13
|
||||
|
||||
proc q*(x: int): int = 6
|
||||
proc q*(x: string): string = "8"
|
||||
10
tests/compile/texport.nim
Normal file
10
tests/compile/texport.nim
Normal file
@@ -0,0 +1,10 @@
|
||||
discard """
|
||||
output: "my object68"
|
||||
"""
|
||||
|
||||
import mexporta
|
||||
|
||||
# B.TMyObject has been imported implicitly here:
|
||||
var x: TMyObject
|
||||
echo($x, q(0), q"0")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# iterate over all files with a given filter:
|
||||
|
||||
import
|
||||
os, times
|
||||
"../../lib/pure/os.nim", ../../ lib / pure / times
|
||||
|
||||
proc main(filter: string) =
|
||||
for filename in walkFiles(filter):
|
||||
|
||||
4
todo.txt
4
todo.txt
@@ -1,7 +1,7 @@
|
||||
version 0.9.2
|
||||
=============
|
||||
|
||||
- 'export' feature
|
||||
- fix tfShared and tfNotNil
|
||||
- test&finish first class iterators:
|
||||
* nested iterators
|
||||
* test generic iterators
|
||||
@@ -50,7 +50,7 @@ Concurrency
|
||||
provide a ``syncgc`` pragma to trigger compiler injection --> more general:
|
||||
an ``injectLoop`` pragma
|
||||
- 'writes: []' effect; track reads/writes for shared types
|
||||
- use the effect system to for static deadlock prevention
|
||||
- use the effect system for static deadlock prevention
|
||||
|
||||
|
||||
version 0.9.XX
|
||||
|
||||
@@ -51,6 +51,9 @@ Language Additions
|
||||
that ``nil`` is not allowed. However currently the compiler performs no
|
||||
advanced static checking for this; for now it's merely for documentation
|
||||
purposes.
|
||||
- An ``export`` statement has been added to the language: It can be used for
|
||||
symbol forwarding so client modules don't have to import a module's
|
||||
dependencies explicitly.
|
||||
|
||||
|
||||
2012-09-23 Version 0.9.0 released
|
||||
|
||||
Reference in New Issue
Block a user