From f503439e811d822f19daa9591cb3bd9e90edabe7 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 30 Nov 2012 19:57:23 +0100 Subject: [PATCH 1/4] implements 'import dir/module' without quotes --- compiler/importer.nim | 8 +++++--- tests/compile/twalker.nim | 2 +- todo.txt | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/importer.nim b/compiler/importer.nim index b3821746c2..11fc456016 100755 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -29,9 +29,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 diff --git a/tests/compile/twalker.nim b/tests/compile/twalker.nim index 3fdd8769ba..89e6c2b9d5 100755 --- a/tests/compile/twalker.nim +++ b/tests/compile/twalker.nim @@ -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): diff --git a/todo.txt b/todo.txt index 804f6e5f68..e6731582f7 100755 --- a/todo.txt +++ b/todo.txt @@ -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 From 336da8f44e28da0cc4f51933f52b836f7e2e9c59 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 1 Dec 2012 16:04:59 +0000 Subject: [PATCH 2/4] IRC module is now saner at the expense of a little API breakage. Added warnings for unstable APIs to modules that use AsyncIO. --- lib/pure/asyncio.nim | 3 + lib/pure/ftpclient.nim | 4 + lib/pure/httpserver.nim | 2 + lib/pure/irc.nim | 193 +++++++++++++++++++++------------------- lib/pure/scgi.nim | 2 + 5 files changed, 111 insertions(+), 93 deletions(-) diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim index 5ecc16de7b..0f51977929 100644 --- a/lib/pure/asyncio.nim +++ b/lib/pure/asyncio.nim @@ -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 ## ==================== ## diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim index 410c5e8bca..78c96c3f11 100644 --- a/lib/pure/ftpclient.nim +++ b/lib/pure/ftpclient.nim @@ -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 diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim index 9d9ea2012a..ce816b7d4b 100755 --- a/lib/pure/httpserver.nim +++ b/lib/pure/httpserver.nim @@ -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 diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim index 81a1befb51..11808ca33c 100644 --- a/lib/pure/irc.nim +++ b/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 @@ -254,8 +281,8 @@ proc processLine(irc: var TIRC, line: string): TIRCEvent = result.typ = EvDisconnected return - if result.cmd == MPing: - irc.send("PONG " & result.params[0]) + #if result.cmd == MPing: + # irc.send("PONG " & result.params[0]) if result.cmd == MPong: irc.lag = epochTime() - parseFloat(result.params[result.params.high]) irc.lastPong = epochTime() @@ -271,11 +298,11 @@ 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() - irc.send("PING :" & formatFloat(irc.lastPing), true) + #if epochTime() - irc.lastPing >= 20.0: + # irc.lastPing = epochTime() + # irc.send("PING :" & formatFloat(irc.lastPing), true) if epochTime() - irc.lastPong >= 120.0 and irc.lastPong != -1.0: irc.close() @@ -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)") diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim index 44a579a7d7..0f3b44e000 100755 --- a/lib/pure/scgi.nim +++ b/lib/pure/scgi.nim @@ -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 From 10d13d5032bd1109207a9feb9f487ad5d7e102de Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 1 Dec 2012 16:38:33 +0000 Subject: [PATCH 3/4] Fixed IRC test. --- lib/pure/irc.nim | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim index 11808ca33c..8916681f7e 100644 --- a/lib/pure/irc.nim +++ b/lib/pure/irc.nim @@ -281,8 +281,8 @@ proc processLine(irc: PIRC, line: string): TIRCEvent = result.typ = EvDisconnected return - #if result.cmd == MPing: - # irc.send("PONG " & result.params[0]) + if result.cmd == MPing: + irc.send("PONG " & result.params[0]) if result.cmd == MPong: irc.lag = epochTime() - parseFloat(result.params[result.params.high]) irc.lastPong = epochTime() @@ -300,9 +300,9 @@ proc processLine(irc: PIRC, line: string): TIRCEvent = proc processOther(irc: PIRC, ev: var TIRCEvent): bool = result = false - #if epochTime() - irc.lastPing >= 20.0: - # irc.lastPing = epochTime() - # irc.send("PING :" & formatFloat(irc.lastPing), true) + if epochTime() - irc.lastPing >= 20.0: + irc.lastPing = epochTime() + irc.send("PING :" & formatFloat(irc.lastPing), true) if epochTime() - irc.lastPong >= 120.0 and irc.lastPong != -1.0: irc.close() @@ -463,6 +463,8 @@ when isMainModule: var event: TIRCEvent if client.poll(event): case event.typ + of EvConnected: + nil of EvDisconnected: break of EvMsg: From c98e3d2c274ac4bd4227d4e3f7e0d2636827f88c Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 1 Dec 2012 19:10:47 +0100 Subject: [PATCH 4/4] implements 'export' feature --- compiler/astalgo.nim | 17 ++++---- compiler/importer.nim | 71 +++++++++++++++++++------------- compiler/semexprs.nim | 23 +++++++++++ doc/manual.txt | 31 +++++++++++++- lib/pure/collections/intsets.nim | 5 +++ tests/compile/mexporta.nim | 8 ++++ tests/compile/mexportb.nim | 7 ++++ tests/compile/texport.nim | 10 +++++ todo.txt | 2 +- web/news.txt | 3 ++ 10 files changed, 137 insertions(+), 40 deletions(-) create mode 100644 tests/compile/mexporta.nim create mode 100644 tests/compile/mexportb.nim create mode 100644 tests/compile/texport.nim diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index da0de3e942..9a2bebab4c 100755 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -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) diff --git a/compiler/importer.nim b/compiler/importer.nim index 11fc456016..774bcea6ac 100755 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -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 @@ -42,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) @@ -98,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 @@ -118,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: @@ -132,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 @@ -157,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) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 9f2b431f69..7acfb830fb 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1657,6 +1657,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..