Merge branch 'bigbreak' of https://github.com/Araq/Nimrod into bigbreak

This commit is contained in:
Araq 2014-09-10 22:56:26 +02:00
commit 758d8e11d9
17 changed files with 153 additions and 97 deletions

View file

@ -374,11 +374,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
cleanPlainSymbol = renderPlainSymbolName(nameNode) cleanPlainSymbol = renderPlainSymbolName(nameNode)
complexSymbol = complexName(k, n, cleanPlainSymbol) complexSymbol = complexName(k, n, cleanPlainSymbol)
plainSymbolRope = toRope(cleanPlainSymbol) plainSymbolRope = toRope(cleanPlainSymbol)
plainSymbolEncRope = toRope(URLencode(cleanPlainSymbol)) plainSymbolEncRope = toRope(urlEncode(cleanPlainSymbol))
itemIDRope = toRope(d.id) itemIDRope = toRope(d.id)
symbolOrId = d.newUniquePlainSymbol(complexSymbol) symbolOrId = d.newUniquePlainSymbol(complexSymbol)
symbolOrIdRope = symbolOrId.toRope symbolOrIdRope = symbolOrId.toRope
symbolOrIdEncRope = URLencode(symbolOrId).toRope symbolOrIdEncRope = urlEncode(symbolOrId).toRope
var seeSrcRope: PRope = nil var seeSrcRope: PRope = nil
let docItemSeeSrc = getConfigVar("doc.item.seesrc") let docItemSeeSrc = getConfigVar("doc.item.seesrc")

View file

@ -796,6 +796,7 @@ else:
else: else:
# FD no longer a part of the selector. Likely been closed # FD no longer a part of the selector. Likely been closed
# (e.g. socket disconnected). # (e.g. socket disconnected).
discard
processTimers(p) processTimers(p)
@ -972,29 +973,50 @@ template createCb*(retFutureSym, iteratorNameSym,
cb() cb()
#{.pop.} #{.pop.}
proc generateExceptionCheck(futSym, proc generateExceptionCheck(futSym,
exceptBranch, rootReceiver, fromNode: PNimrodNode): PNimrodNode {.compileTime.} = tryStmt, rootReceiver, fromNode: PNimrodNode): PNimrodNode {.compileTime.} =
if exceptBranch == nil: if tryStmt.kind == nnkNilLit:
result = rootReceiver result = rootReceiver
else: else:
var exceptionChecks: seq[tuple[cond, body: PNimrodNode]] = @[]
let errorNode = newDotExpr(futSym, newIdentNode("error"))
for i in 1 .. <tryStmt.len:
let exceptBranch = tryStmt[i]
if exceptBranch[0].kind == nnkStmtList: if exceptBranch[0].kind == nnkStmtList:
result = newIfStmt( exceptionChecks.add((newIdentNode("true"), exceptBranch[0]))
(newDotExpr(futSym, newIdentNode("failed")),
exceptBranch[0]
)
)
else: else:
expectKind(exceptBranch[1], nnkStmtList) var exceptIdentCount = 0
result = newIfStmt( var ifCond: PNimrodNode
(newDotExpr(futSym, newIdentNode("failed")), for i in 0 .. <exceptBranch.len:
newIfStmt( let child = exceptBranch[i]
(infix(newDotExpr(futSym, newIdentNode("error")), "of", exceptBranch[0]), if child.kind == nnkIdent:
exceptBranch[1]) let cond = infix(errorNode, "of", child)
) if exceptIdentCount == 0:
) ifCond = cond
) else:
ifCond = infix(ifCond, "or", cond)
else:
break
exceptIdentCount.inc
expectKind(exceptBranch[exceptIdentCount], nnkStmtList)
exceptionChecks.add((ifCond, exceptBranch[exceptIdentCount]))
# -> -> else: raise futSym.error
exceptionChecks.add((newIdentNode("true"),
newNimNode(nnkRaiseStmt).add(errorNode)))
# Read the future if there is no error.
# -> else: futSym.read
let elseNode = newNimNode(nnkElse, fromNode) let elseNode = newNimNode(nnkElse, fromNode)
elseNode.add newNimNode(nnkStmtList, fromNode) elseNode.add newNimNode(nnkStmtList, fromNode)
elseNode[0].add rootReceiver elseNode[0].add rootReceiver
let ifBody = newStmtList()
ifBody.add newCall(newIdentNode("setCurrentException"), errorNode)
ifBody.add newIfStmt(exceptionChecks)
ifBody.add newCall(newIdentNode("setCurrentException"), newNilLit())
result = newIfStmt(
(newDotExpr(futSym, newIdentNode("failed")), ifBody)
)
result.add elseNode result.add elseNode
template createVar(result: var PNimrodNode, futSymName: string, template createVar(result: var PNimrodNode, futSymName: string,
@ -1006,11 +1028,11 @@ template createVar(result: var PNimrodNode, futSymName: string,
result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
result.add newNimNode(nnkYieldStmt, fromNode).add(futSym) # -> yield future<x> result.add newNimNode(nnkYieldStmt, fromNode).add(futSym) # -> yield future<x>
valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future<x>.read valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future<x>.read
result.add generateExceptionCheck(futSym, exceptBranch, rootReceiver, fromNode) result.add generateExceptionCheck(futSym, tryStmt, rootReceiver, fromNode)
proc processBody(node, retFutureSym: PNimrodNode, proc processBody(node, retFutureSym: PNimrodNode,
subTypeIsVoid: bool, subTypeIsVoid: bool,
exceptBranch: PNimrodNode): PNimrodNode {.compileTime.} = tryStmt: PNimrodNode): PNimrodNode {.compileTime.} =
#echo(node.treeRepr) #echo(node.treeRepr)
result = node result = node
case node.kind case node.kind
@ -1024,7 +1046,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
result.add newCall(newIdentNode("complete"), retFutureSym) result.add newCall(newIdentNode("complete"), retFutureSym)
else: else:
result.add newCall(newIdentNode("complete"), retFutureSym, result.add newCall(newIdentNode("complete"), retFutureSym,
node[0].processBody(retFutureSym, subTypeIsVoid, exceptBranch)) node[0].processBody(retFutureSym, subTypeIsVoid, tryStmt))
result.add newNimNode(nnkReturnStmt, node).add(newNilLit()) result.add newNimNode(nnkReturnStmt, node).add(newNilLit())
return # Don't process the children of this return stmt return # Don't process the children of this return stmt
@ -1079,7 +1101,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
res: PNimrodNode): bool {.compileTime.} = res: PNimrodNode): bool {.compileTime.} =
result = false result = false
while i < n[0].len: while i < n[0].len:
var processed = processBody(n[0][i], retFutureSym, subTypeIsVoid, n[1]) var processed = processBody(n[0][i], retFutureSym, subTypeIsVoid, n)
if processed.kind != n[0][i].kind or processed.len != n[0][i].len: if processed.kind != n[0][i].kind or processed.len != n[0][i].len:
expectKind(processed, nnkStmtList) expectKind(processed, nnkStmtList)
expectKind(processed[2][1], nnkElse) expectKind(processed[2][1], nnkElse)
@ -1099,7 +1121,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
else: discard else: discard
for i in 0 .. <result.len: for i in 0 .. <result.len:
result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, exceptBranch) result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, tryStmt)
proc getName(node: PNimrodNode): string {.compileTime.} = proc getName(node: PNimrodNode): string {.compileTime.} =
case node.kind case node.kind
@ -1193,7 +1215,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
result[6] = outerProcBody result[6] = outerProcBody
#echo(treeRepr(result)) #echo(treeRepr(result))
#if prc[0].getName == "getFile": #if prc[0].getName == "catch":
# echo(toStrLit(result)) # echo(toStrLit(result))
proc recvLine*(socket: TAsyncFD): Future[string] {.async.} = proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
@ -1209,6 +1231,8 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
## If the socket is disconnected in the middle of a line (before ``\r\L`` ## If the socket is disconnected in the middle of a line (before ``\r\L``
## is read) then line will be set to ``""``. ## is read) then line will be set to ``""``.
## The partial line **will be lost**. ## The partial line **will be lost**.
##
## **Warning**: This assumes that lines are delimited by ``\r\l``.
template addNLIfEmpty(): stmt = template addNLIfEmpty(): stmt =
if result.len == 0: if result.len == 0:
@ -1221,9 +1245,8 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
if c.len == 0: if c.len == 0:
return "" return ""
if c == "\r": if c == "\r":
c = await recv(socket, 1, {SocketFlag.SafeDisconn, SocketFlag.Peek}) c = await recv(socket, 1)
if c.len > 0 and c == "\L": assert c == "\l"
discard await recv(socket, 1)
addNLIfEmpty() addNLIfEmpty()
return return
elif c == "\L": elif c == "\L":

View file

@ -34,26 +34,7 @@ type
fd: TAsyncFd fd: TAsyncFd
offset: int64 offset: int64
# TODO: These will be nil in other threads?
var
asyncStdin* {.threadvar.}: AsyncFile ## Asynchronous stdin handle
asyncStdout* {.threadvar.}: AsyncFile ## Asynchronous stdout handle
asyncStderr* {.threadvar.}: AsyncFile ## Asynchronous stderr handle
when defined(windows): when defined(windows):
asyncStdin = AsyncFile(
fd: getStdHandle(STD_INPUT_HANDLE).TAsyncFd,
offset: 0
)
asyncStdout = AsyncFile(
fd: getStdHandle(STD_OUTPUT_HANDLE).TAsyncFd,
offset: 0
)
asyncStderr = AsyncFile(
fd: getStdHandle(STD_ERROR_HANDLE).TAsyncFd,
offset: 0
)
proc getDesiredAccess(mode: TFileMode): int32 = proc getDesiredAccess(mode: TFileMode): int32 =
case mode case mode
of fmRead: of fmRead:
@ -73,19 +54,6 @@ when defined(windows):
else: else:
CREATE_NEW CREATE_NEW
else: else:
asyncStdin = AsyncFile(
fd: STDIN_FILENO.TAsyncFd,
offset: 0
)
asyncStdout = AsyncFile(
fd: STDOUT_FILENO.TAsyncFd,
offset: 0
)
asyncStderr = AsyncFile(
fd: STDERR_FILENO.TAsyncFd,
offset: 0
)
proc getPosixFlags(mode: TFileMode): cint = proc getPosixFlags(mode: TFileMode): cint =
case mode case mode
of fmRead: of fmRead:
@ -100,7 +68,7 @@ else:
result = O_RDWR result = O_RDWR
result = result or O_NONBLOCK result = result or O_NONBLOCK
proc getFileSize*(f: AsyncFile): int64 = proc getFileSize(f: AsyncFile): int64 =
## Retrieves the specified file's size. ## Retrieves the specified file's size.
when defined(windows): when defined(windows):
var high: DWord var high: DWord

View file

@ -183,6 +183,7 @@ proc processClient(client: PAsyncSocket, address: string,
# header states otherwise. # header states otherwise.
# In HTTP 1.0 we assume that the connection should not be persistent. # In HTTP 1.0 we assume that the connection should not be persistent.
# Unless the connection header states otherwise. # Unless the connection header states otherwise.
discard
else: else:
request.client.close() request.client.close()
break break

View file

@ -247,6 +247,7 @@ proc asyncSockHandleWrite(h: RootRef) =
# Apparently the socket cannot be written to. Even though select # Apparently the socket cannot be written to. Even though select
# just told us that it can be... This used to be an assert. Just # just told us that it can be... This used to be an assert. Just
# do nothing instead. # do nothing instead.
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:

View file

@ -31,7 +31,7 @@
import strutils, os, strtabs, cookies import strutils, os, strtabs, cookies
proc URLencode*(s: string): string = proc urlEncode*(s: string): string =
## Encodes a value to be HTTP safe: This means that characters in the set ## Encodes a value to be HTTP safe: This means that characters in the set
## ``{'A'..'Z', 'a'..'z', '0'..'9', '_'}`` are carried over to the result, ## ``{'A'..'Z', 'a'..'z', '0'..'9', '_'}`` are carried over to the result,
## a space is converted to ``'+'`` and every other character is encoded as ## a space is converted to ``'+'`` and every other character is encoded as
@ -52,7 +52,7 @@ proc handleHexChar(c: char, x: var int) {.inline.} =
of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
else: assert(false) else: assert(false)
proc URLdecode*(s: string): string = proc urlDecode*(s: string): string =
## Decodes a value from its HTTP representation: This means that a ``'+'`` ## Decodes a value from its HTTP representation: This means that a ``'+'``
## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal ## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal
## value) is converted to the character with ordinal number ``xx``, and ## value) is converted to the character with ordinal number ``xx``, and
@ -82,7 +82,7 @@ proc addXmlChar(dest: var string, c: char) {.inline.} =
of '\"': add(dest, "&quot;") of '\"': add(dest, "&quot;")
else: add(dest, c) else: add(dest, c)
proc XMLencode*(s: string): string = proc xmlEncode*(s: string): string =
## Encodes a value to be XML safe: ## Encodes a value to be XML safe:
## * ``"`` is replaced by ``&quot;`` ## * ``"`` is replaced by ``&quot;``
## * ``<`` is replaced by ``&lt;`` ## * ``<`` is replaced by ``&lt;``
@ -99,7 +99,8 @@ type
methodPost, ## query uses the POST method methodPost, ## query uses the POST method
methodGet ## query uses the GET method methodGet ## query uses the GET method
{.deprecated: [TRequestMethod: RequestMethod, ECgi: CgiError].} {.deprecated: [TRequestMethod: RequestMethod, ECgi: CgiError,
URLencode: urlEncode, XMLencode: xmlEncode, URLdecode: urlDecode].}
proc cgiError*(msg: string) {.noreturn.} = proc cgiError*(msg: string) {.noreturn.} =
## raises an ECgi exception with message `msg`. ## raises an ECgi exception with message `msg`.
@ -331,9 +332,9 @@ proc setTestData*(keysvalues: varargs[string]) =
var i = 0 var i = 0
var query = "" var query = ""
while i < keysvalues.len: while i < keysvalues.len:
add(query, URLencode(keysvalues[i])) add(query, urlEncode(keysvalues[i]))
add(query, '=') add(query, '=')
add(query, URLencode(keysvalues[i+1])) add(query, urlEncode(keysvalues[i+1]))
add(query, '&') add(query, '&')
inc(i, 2) inc(i, 2)
putEnv("QUERY_STRING", query) putEnv("QUERY_STRING", query)

View file

@ -2631,6 +2631,12 @@ when not defined(JS): #and not defined(NimrodVM):
excHandler.hasRaiseAction = true excHandler.hasRaiseAction = true
excHandler.raiseAction = action excHandler.raiseAction = action
proc setCurrentException*(exc: ref Exception) {.inline, gcsafe.} =
## sets the current exception.
##
## **Warning**: Only use this if you know what you are doing.
currException = exc
{.push stack_trace: off, profiler:off.} {.push stack_trace: off, profiler:off.}
when defined(endb) and not defined(NimrodVM): when defined(endb) and not defined(NimrodVM):
include "system/debugger" include "system/debugger"

View file

@ -21,15 +21,8 @@ proc launchSwarm(port: TPort) {.async.} =
var sock = newAsyncRawSocket() var sock = newAsyncRawSocket()
await connect(sock, "localhost", port) await connect(sock, "localhost", port)
when true:
await sendMessages(sock) await sendMessages(sock)
closeSocket(sock) closeSocket(sock)
else:
# Issue #932: https://github.com/Araq/Nim/issues/932
var msgFut = sendMessages(sock)
msgFut.callback =
proc () =
closeSocket(sock)
proc readMessages(client: TAsyncFD) {.async.} = proc readMessages(client: TAsyncFD) {.async.} =
while true: while true:
@ -47,18 +40,18 @@ proc readMessages(client: TAsyncFD) {.async.} =
proc createServer(port: TPort) {.async.} = proc createServer(port: TPort) {.async.} =
var server = newAsyncRawSocket() var server = newAsyncRawSocket()
block: block:
var name: TSockaddr_in var name: Sockaddr_in
when defined(windows): when defined(windows):
name.sin_family = toInt(AF_INET).int16 name.sin_family = toInt(AF_INET).int16
else: else:
name.sin_family = toInt(AF_INET) name.sin_family = toInt(AF_INET)
name.sin_port = htons(int16(port)) name.sin_port = htons(int16(port))
name.sin_addr.s_addr = htonl(INADDR_ANY) name.sin_addr.s_addr = htonl(INADDR_ANY)
if bindAddr(server.TSocketHandle, cast[ptr TSockAddr](addr(name)), if bindAddr(server.SocketHandle, cast[ptr SockAddr](addr(name)),
sizeof(name).TSocklen) < 0'i32: sizeof(name).Socklen) < 0'i32:
osError(osLastError()) raiseOSError(osLastError())
discard server.TSocketHandle.listen() discard server.SocketHandle.listen()
while true: while true:
var client = await accept(server) var client = await accept(server)
asyncCheck readMessages(client) asyncCheck readMessages(client)

View file

@ -13,7 +13,7 @@ discard """
import asyncio, asyncdispatch, asyncnet import asyncio, asyncdispatch, asyncnet
proc main {.async.} = proc main {.async.} =
proc f: PFuture[int] {.async.} = proc f: Future[int] {.async.} =
discard discard
echo 1 echo 1
discard discard
@ -24,7 +24,7 @@ proc main {.async.} =
echo x echo x
echo 3 echo 3
proc g: PFuture[int] {.async.} = proc g: Future[int] {.async.} =
discard discard
echo 4 echo 4
discard discard

View file

@ -1,15 +1,15 @@
discard """ discard """
file: "tasyncexceptions.nim" file: "tasyncexceptions.nim"
exitcode: 1 exitcode: 1
outputsub: "Error: unhandled exception: foobar [E_Base]" outputsub: "Error: unhandled exception: foobar [Exception]"
""" """
import asyncdispatch import asyncdispatch
proc accept(): PFuture[int] {.async.} = proc accept(): Future[int] {.async.} =
await sleepAsync(100) await sleepAsync(100)
result = 4 result = 4
proc recvLine(fd: int): PFuture[string] {.async.} = proc recvLine(fd: int): Future[string] {.async.} =
await sleepAsync(100) await sleepAsync(100)
return "get" return "get"

View file

@ -1,5 +1,5 @@
discard """ discard """
file: "tasyncexceptions.nim" file: "tasyncfile.nim"
exitcode: 0 exitcode: 0
""" """
import asyncfile, asyncdispatch, os import asyncfile, asyncdispatch, os

51
tests/async/tasynctry.nim Normal file
View file

@ -0,0 +1,51 @@
discard """
file: "tasynctry.nim"
exitcode: 0
output: '''
Generic except: Test
Specific except
Multiple idents in except
Multiple except branches
Multiple except branches 2
'''
"""
import asyncdispatch
# Here we are testing the ability to catch exceptions.
proc foobar() {.async.} =
if 5 == 5:
raise newException(EInvalidIndex, "Test")
proc catch() {.async.} =
# TODO: Create a test for when exceptions are not caught.
try:
await foobar()
except:
echo("Generic except: ", getCurrentExceptionMsg())
try:
await foobar()
except EInvalidIndex:
echo("Specific except")
try:
await foobar()
except OSError, EInvalidField, EInvalidIndex:
echo("Multiple idents in except")
try:
await foobar()
except OSError, EInvalidField:
assert false
except EInvalidIndex:
echo("Multiple except branches")
try:
await foobar()
except EInvalidIndex:
echo("Multiple except branches 2")
except OSError, EInvalidField:
assert false
asyncCheck catch()

View file

@ -1,8 +1,8 @@
import asyncdispatch, asyncnet import asyncdispatch, asyncnet
proc main {.async.} = proc main {.async.} =
proc f: PFuture[seq[int]] {.async.} = proc f: Future[seq[int]] {.async.} =
await newAsyncSocket().connect("www.google.com", TPort(80)) await newAsyncSocket().connect("www.google.com", Port(80))
let x = await f() let x = await f()
asyncCheck main() asyncCheck main()

View file

@ -107,7 +107,7 @@ div.tabContent.hide { display: none; }
HtmlEnd = "</body></html>" HtmlEnd = "</body></html>"
proc td(s: string): string = proc td(s: string): string =
result = "<td>" & s.substr(0, 200).XMLEncode & "</td>" result = "<td>" & s.substr(0, 200).xmlEncode & "</td>"
proc getCommit(db: TDbConn, c: int): string = proc getCommit(db: TDbConn, c: int): string =
var commit = c var commit = c

View file

@ -37,7 +37,7 @@ proc asmx64 () {.compileTime} =
proc abortAsmParse (err:string) = proc abortAsmParse (err:string) =
# discard
let codeLen = code.len let codeLen = code.len
#let codeEnd = codeLen-1 #let codeEnd = codeLen-1

View file

@ -121,8 +121,8 @@ Bleeding edge binaries are available from the `Nimrod build farm <http://build.n
Source Source
====== ======
Starting with 0.9.4 we now advise people to build directly from the Use the following commands to build the compiler from source.
github `master <https://github.com/Araq/Nimrod#compiling>`_ branch:: Change the branch to suit your needs::
git clone -b master git://github.com/Araq/Nimrod.git git clone -b master git://github.com/Araq/Nimrod.git
cd Nimrod cd Nimrod

View file

@ -14,8 +14,12 @@ News
``threadpool``. ``threadpool``.
- The symbol binding rules in generics changed: ``bar`` in ``foo.bar`` is - The symbol binding rules in generics changed: ``bar`` in ``foo.bar`` is
now considered for implicit early binding. now considered for implicit early binding.
- ``c2nim`` moved into its own repository and is now a Babel package. - ``c2nim`` moved into its own
- ``pas2nim`` moved into its own repository and is now a Babel package. `repository <https://github.com/nimrod-code/c2nim>`_
and is now a Nimble package.
- ``pas2nim`` moved into its own
`repository <https://github.com/nimrod-code/pas2nim>`_
and is now a Nimble package.
- ``system.$`` for floating point types now produces a human friendly string - ``system.$`` for floating point types now produces a human friendly string
representation. representation.
- ``uri.TUrl`` as well as the ``parseurl`` module are now deprecated in favour - ``uri.TUrl`` as well as the ``parseurl`` module are now deprecated in favour
@ -31,7 +35,15 @@ News
will disappear soon! will disappear soon!
- ``system.fileHandle`` has been renamed to ``system.getFileHandle`` to - ``system.fileHandle`` has been renamed to ``system.getFileHandle`` to
prevent name conflicts with the new type ``FileHandle``. prevent name conflicts with the new type ``FileHandle``.
- Comments are now not part of the AST, as such you cannot use them in place
of ``discard``.
- The ``irc`` module has been moved into its own
`repository <https://github.com/nimrod-code/irc>`_
and is now a Nimble package.
- Many wrappers have been moved into their own repositories and are now
Nimble packages including ``lua``, ``opengl``, ``x11``, ``nim-zmq``,
``gtk2``, ``mongo``, ``cairo``, ``tcl`` and ``python``. They can be
found under the `nim-code <https://github.com/nimrod-code>`_ organisation.
Language Additions Language Additions
------------------ ------------------