Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
Araq
2012-12-02 11:13:05 +01:00
16 changed files with 252 additions and 133 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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:

View File

@@ -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

View File

@@ -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
## ====================
##

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -0,0 +1,8 @@
# module A
import mexportb
export mexportb.TMyObject, mexportb.xyz
export mexportb.q
proc `$`*(x: TMyObject): string = "my object"

View 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
View 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")

View File

@@ -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):

View File

@@ -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

View File

@@ -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