Merge branch 'devel' of github.com:nim-lang/Nim into devel

This commit is contained in:
Andreas Rumpf
2016-02-06 15:29:25 +01:00
50 changed files with 224 additions and 202 deletions

View File

@@ -40,7 +40,7 @@ type
Actor[In, Out] = object{.pure, final.}
i: Channel[Task[In, Out]]
t: TThread[ptr Actor[In, Out]]
t: Thread[ptr Actor[In, Out]]
PActor*[In, Out] = ptr Actor[In, Out] ## an actor
{.deprecated: [TTask: Task, TActor: Actor].}

View File

@@ -39,7 +39,6 @@ when hostOS == "solaris":
import os, parseutils
from times import epochTime
import unsigned
when defined(ssl):
import openssl

View File

@@ -10,7 +10,6 @@
from pcre import nil
import nre.private.util
import tables
import unsigned
from strutils import toLower, `%`
from math import ceil
import options

View File

@@ -1518,7 +1518,7 @@ proc dirInclude(p: var RstParser): PRstNode =
# InternalError("Too many binary zeros in include file")
result = parseDoc(q)
proc dirCodeBlock(p: var RstParser, nimrodExtension = false): PRstNode =
proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode =
## Parses a code block.
##
## Code blocks are rnDirective trees with a `kind` of rnCodeBlock. See the
@@ -1526,8 +1526,8 @@ proc dirCodeBlock(p: var RstParser, nimrodExtension = false): PRstNode =
##
## Code blocks can come in two forms, the standard `code directive
## <http://docutils.sourceforge.net/docs/ref/rst/directives.html#code>`_ and
## the nimrod extension ``.. code-block::``. If the block is an extension, we
## want the default language syntax highlighting to be Nimrod, so we create a
## the nim extension ``.. code-block::``. If the block is an extension, we
## want the default language syntax highlighting to be Nim, so we create a
## fake internal field to comminicate with the generator. The field is named
## ``default-language``, which is unlikely to collide with a field specified
## by any random rst input file.
@@ -1545,16 +1545,16 @@ proc dirCodeBlock(p: var RstParser, nimrodExtension = false): PRstNode =
result.sons[2] = n
# Extend the field block if we are using our custom extension.
if nimrodExtension:
if nimExtension:
# Create a field block if the input block didn't have any.
if result.sons[1].isNil: result.sons[1] = newRstNode(rnFieldList)
assert result.sons[1].kind == rnFieldList
# Hook the extra field and specify the Nimrod language as value.
# Hook the extra field and specify the Nim language as value.
var extraNode = newRstNode(rnField)
extraNode.add(newRstNode(rnFieldName))
extraNode.add(newRstNode(rnFieldBody))
extraNode.sons[0].add(newRstNode(rnLeaf, "default-language"))
extraNode.sons[1].add(newRstNode(rnLeaf, "Nimrod"))
extraNode.sons[1].add(newRstNode(rnLeaf, "Nim"))
result.sons[1].add(extraNode)
result.kind = rnCodeBlock
@@ -1641,7 +1641,7 @@ proc parseDotDot(p: var RstParser): PRstNode =
else:
rstMessage(p, meInvalidDirective, d)
of dkCode: result = dirCodeBlock(p)
of dkCodeBlock: result = dirCodeBlock(p, nimrodExtension = true)
of dkCodeBlock: result = dirCodeBlock(p, nimExtension = true)
of dkIndex: result = dirIndex(p)
else: rstMessage(p, meInvalidDirective, d)
popInd(p)

View File

@@ -757,10 +757,15 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
template valid(s): expr =
s.len > 0 and allCharsInSet(s, {'.','/',':','%','_','\\','\128'..'\xFF'} +
Digits + Letters + WhiteSpace)
var options = ""
let
arg = getArgument(n)
isObject = arg.toLower().endsWith(".svg")
var
options = ""
content = ""
var s = getFieldValue(n, "scale")
if s.valid: dispA(d.target, options, " scale=\"$1\"", " scale=$1", [strip(s)])
if s.valid: dispA(d.target, options, if isObject: "" else: " scale=\"$1\"",
" scale=$1", [strip(s)])
s = getFieldValue(n, "height")
if s.valid: dispA(d.target, options, " height=\"$1\"", " height=$1", [strip(s)])
@@ -769,16 +774,21 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
if s.valid: dispA(d.target, options, " width=\"$1\"", " width=$1", [strip(s)])
s = getFieldValue(n, "alt")
if s.valid: dispA(d.target, options, " alt=\"$1\"", "", [strip(s)])
if s.valid:
# <object> displays its content if it cannot render the image
if isObject: dispA(d.target, content, "$1", "", [strip(s)])
else: dispA(d.target, options, " alt=\"$1\"", "", [strip(s)])
s = getFieldValue(n, "align")
if s.valid: dispA(d.target, options, " align=\"$1\"", "", [strip(s)])
if options.len > 0: options = dispF(d.target, "$1", "[$1]", [options])
let arg = getArgument(n)
if arg.valid:
dispA(d.target, result, "<img src=\"$1\"$2 />", "\\includegraphics$2{$1}",
let htmlOut = if isObject:
"<object data=\"$1\" type=\"image/svg+xml\"$2 >" & content & "</object>"
else: "<img src=\"$1\"$2 />"
dispA(d.target, result, htmlOut, "\\includegraphics$2{$1}",
[arg, options])
if len(n) >= 3: renderRstToOut(d, n.sons[2], result)
@@ -802,7 +812,7 @@ proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) =
if parseInt(n.getFieldValue, number) > 0:
params.startLine = number
of "file":
# The ``file`` option is a Nimrod extension to the official spec, it acts
# The ``file`` option is a Nim extension to the official spec, it acts
# like it would for other directives like ``raw`` or ``cvs-table``. This
# field is dealt with in ``rst.nim`` which replaces the existing block with
# the referenced file, so we only need to ignore it here to avoid incorrect
@@ -871,7 +881,7 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
## second the code block itself. The code block can use syntax highlighting,
## which depends on the directive argument specified by the rst input, and
## may also come from the parser through the internal ``default-language``
## option to differentiate between a plain code block and nimrod's code block
## option to differentiate between a plain code block and Nim's code block
## extension.
assert n.kind == rnCodeBlock
if n.sons[2] == nil: return

View File

@@ -1,6 +1,6 @@
#nim c -t:-march=i686 --cpu:amd64 --threads:on -d:release lockfreehash.nim
import unsigned, math, hashes
import math, hashes
#------------------------------------------------------------------------------
## Memory Utility Functions

View File

@@ -951,7 +951,7 @@ when isMainModule and not defined(release):
var b = initOrderedSet[int]()
for x in [2, 4, 5]: b.incl(x)
assert($a == $b)
assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
assert(a == b) # https://github.com/Araq/Nim/issues/1413
block initBlocks:
var a: OrderedSet[int]

View File

@@ -6,7 +6,7 @@
# distribution, for details about the copyright.
#
## This module implements color handling for Nimrod. It is used by
## This module implements color handling for Nim. It is used by
## the ``graphics`` module.
import strutils

View File

@@ -328,10 +328,10 @@ proc distinguishedSlave(w: ptr Worker) {.thread.} =
if w.q.len != 0: w.cleanFlowVars
var
workers: array[MaxThreadPoolSize, TThread[ptr Worker]]
workers: array[MaxThreadPoolSize, Thread[ptr Worker]]
workersData: array[MaxThreadPoolSize, Worker]
distinguished: array[MaxDistinguishedThread, TThread[ptr Worker]]
distinguished: array[MaxDistinguishedThread, Thread[ptr Worker]]
distinguishedData: array[MaxDistinguishedThread, Worker]
when defined(nimPinToCpu):
@@ -468,7 +468,7 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} =
await(gSomeReady)
var
distinguishedLock: TLock
distinguishedLock: Lock
initLock distinguishedLock

View File

@@ -134,7 +134,7 @@ macro `[]`*(lc: ListComprehension, comp, typ: expr): expr =
## comprehension, for example ``x | (x <- 1..10, x mod 2 == 0)``. `typ` is
## the type that will be stored inside the result seq.
##
## .. code-block:: nimrod
## .. code-block:: nim
##
## echo lc[x | (x <- 1..10, x mod 2 == 0), int]
##

View File

@@ -712,17 +712,21 @@ proc `%`*(elements: openArray[JsonNode]): JsonNode =
proc toJson(x: NimNode): NimNode {.compiletime.} =
case x.kind
of nnkBracket:
of nnkBracket: # array
result = newNimNode(nnkBracket)
for i in 0 .. <x.len:
result.add(toJson(x[i]))
of nnkTableConstr:
of nnkTableConstr: # object
result = newNimNode(nnkTableConstr)
for i in 0 .. <x.len:
assert x[i].kind == nnkExprColonExpr
x[i].expectKind nnkExprColonExpr
result.add(newNimNode(nnkExprColonExpr).add(x[i][0]).add(toJson(x[i][1])))
of nnkCurly: # empty object
result = newNimNode(nnkTableConstr)
x.expectLen(0)
else:
result = x

View File

@@ -1,5 +1,3 @@
import unsigned
type
MersenneTwister* = object
mt: array[0..623, uint32]

View File

@@ -102,8 +102,7 @@ type
## case of IPv4
{.deprecated: [TIpAddress: IpAddress].}
proc isIpAddress*(address_str: string): bool {.tags: [].}
proc parseIpAddress*(address_str: string): IpAddress
proc socketError*(socket: Socket, err: int = -1, async = false,
lastError = (-1).OSErrorCode): void
@@ -548,40 +547,6 @@ proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {
var valuei = cint(if value: 1 else: 0)
setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
proc connect*(socket: Socket, address: string,
port = Port(0)) {.tags: [ReadIOEffect].} =
## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
## host name. If ``address`` is a host name, this function will try each IP
## of that host name. ``htons`` is already performed on ``port`` so you must
## not do it.
##
## If ``socket`` is an SSL socket a handshake will be automatically performed.
var aiList = getAddrInfo(address, port, socket.domain)
# try all possibilities:
var success = false
var lastError: OSErrorCode
var it = aiList
while it != nil:
if connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32:
success = true
break
else: lastError = osLastError()
it = it.ai_next
dealloc(aiList)
if not success: raiseOSError(lastError)
when defined(ssl):
if socket.isSSL:
# RFC3546 for SNI specifies that IP addresses are not allowed.
if not isIpAddress(address):
# Discard result in case OpenSSL version doesn't support SNI, or we're
# not using TLSv1+
discard SSL_set_tlsext_host_name(socket.sslHandle, address)
let ret = SSLConnect(socket.sslHandle)
socketError(socket, ret)
when defined(ssl):
proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} =
## This proc needs to be called on a socket after it connects. This is
@@ -971,61 +936,6 @@ proc sendTo*(socket: Socket, address: string, port: Port,
## This is the high-level version of the above ``sendTo`` function.
result = socket.sendTo(address, port, cstring(data), data.len)
proc connectAsync(socket: Socket, name: string, port = Port(0),
af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
## A variant of ``connect`` for non-blocking sockets.
##
## This procedure will immediately return, it will not block until a connection
## is made. It is up to the caller to make sure the connection has been established
## by checking (using ``select``) whether the socket is writeable.
##
## **Note**: For SSL sockets, the ``handshake`` procedure must be called
## whenever the socket successfully connects to a server.
var aiList = getAddrInfo(name, port, af)
# try all possibilities:
var success = false
var lastError: OSErrorCode
var it = aiList
while it != nil:
var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen)
if ret == 0'i32:
success = true
break
else:
lastError = osLastError()
when useWinVersion:
# Windows EINTR doesn't behave same as POSIX.
if lastError.int32 == WSAEWOULDBLOCK:
success = true
break
else:
if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
success = true
break
it = it.ai_next
dealloc(aiList)
if not success: raiseOSError(lastError)
proc connect*(socket: Socket, address: string, port = Port(0),
timeout: int) {.tags: [ReadIOEffect, WriteIOEffect].} =
## Connects to server as specified by ``address`` on port specified by ``port``.
##
## The ``timeout`` paremeter specifies the time in milliseconds to allow for
## the connection to the server to be made.
socket.fd.setBlocking(false)
socket.connectAsync(address, port, socket.domain)
var s = @[socket.fd]
if selectWrite(s, timeout) != 1:
raise newException(TimeoutError, "Call to 'connect' timed out.")
else:
when defined(ssl):
if socket.isSSL:
socket.fd.setBlocking(true)
doAssert socket.handshake()
socket.fd.setBlocking(true)
proc isSsl*(socket: Socket): bool =
## Determines whether ``socket`` is a SSL socket.
@@ -1295,7 +1205,8 @@ proc parseIPv6Address(address_str: string): IpAddress =
raise newException(ValueError,
"Invalid IP Address. The address consists of too many groups")
proc parseIpAddress(address_str: string): IpAddress =
proc parseIpAddress*(address_str: string): IpAddress =
## Parses an IP address
## Raises EInvalidValue on error
if address_str == nil:
@@ -1305,8 +1216,7 @@ proc parseIpAddress(address_str: string): IpAddress =
else:
return parseIPv4Address(address_str)
proc isIpAddress(address_str: string): bool =
proc isIpAddress*(address_str: string): bool {.tags: [].} =
## Checks if a string is an IP address
## Returns true if it is, false otherwise
try:
@@ -1314,3 +1224,94 @@ proc isIpAddress(address_str: string): bool =
except ValueError:
return false
return true
proc connect*(socket: Socket, address: string,
port = Port(0)) {.tags: [ReadIOEffect].} =
## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
## host name. If ``address`` is a host name, this function will try each IP
## of that host name. ``htons`` is already performed on ``port`` so you must
## not do it.
##
## If ``socket`` is an SSL socket a handshake will be automatically performed.
var aiList = getAddrInfo(address, port, socket.domain)
# try all possibilities:
var success = false
var lastError: OSErrorCode
var it = aiList
while it != nil:
if connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32:
success = true
break
else: lastError = osLastError()
it = it.ai_next
dealloc(aiList)
if not success: raiseOSError(lastError)
when defined(ssl):
if socket.isSSL:
# RFC3546 for SNI specifies that IP addresses are not allowed.
if not isIpAddress(address):
# Discard result in case OpenSSL version doesn't support SNI, or we're
# not using TLSv1+
discard SSL_set_tlsext_host_name(socket.sslHandle, address)
let ret = SSLConnect(socket.sslHandle)
socketError(socket, ret)
proc connectAsync(socket: Socket, name: string, port = Port(0),
af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
## A variant of ``connect`` for non-blocking sockets.
##
## This procedure will immediately return, it will not block until a connection
## is made. It is up to the caller to make sure the connection has been established
## by checking (using ``select``) whether the socket is writeable.
##
## **Note**: For SSL sockets, the ``handshake`` procedure must be called
## whenever the socket successfully connects to a server.
var aiList = getAddrInfo(name, port, af)
# try all possibilities:
var success = false
var lastError: OSErrorCode
var it = aiList
while it != nil:
var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen)
if ret == 0'i32:
success = true
break
else:
lastError = osLastError()
when useWinVersion:
# Windows EINTR doesn't behave same as POSIX.
if lastError.int32 == WSAEWOULDBLOCK:
success = true
break
else:
if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
success = true
break
it = it.ai_next
dealloc(aiList)
if not success: raiseOSError(lastError)
proc connect*(socket: Socket, address: string, port = Port(0),
timeout: int) {.tags: [ReadIOEffect, WriteIOEffect].} =
## Connects to server as specified by ``address`` on port specified by ``port``.
##
## The ``timeout`` paremeter specifies the time in milliseconds to allow for
## the connection to the server to be made.
socket.fd.setBlocking(false)
socket.connectAsync(address, port, socket.domain)
var s = @[socket.fd]
if selectWrite(s, timeout) != 1:
raise newException(TimeoutError, "Call to 'connect' timed out.")
else:
when defined(ssl):
if socket.isSSL:
socket.fd.setBlocking(true)
doAssert socket.handshake()
socket.fd.setBlocking(true)

View File

@@ -774,6 +774,7 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
res: int
res = findFirstFile(pattern, f)
if res != -1:
defer: findClose(res)
while true:
if not skipFindData(f) and
(f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) == 0'i32:
@@ -786,7 +787,6 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
pattern[dotPos+1] == '*':
yield splitFile(pattern).dir / extractFilename(ff)
if findNextFile(res, f) == 0'i32: break
findClose(res)
else: # here we use glob
var
f: Glob
@@ -795,11 +795,11 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
f.gl_pathc = 0
f.gl_pathv = nil
res = glob(pattern, 0, nil, addr(f))
defer: globfree(addr(f))
if res == 0:
for i in 0.. f.gl_pathc - 1:
assert(f.gl_pathv[i] != nil)
yield $f.gl_pathv[i]
globfree(addr(f))
type
PathComponent* = enum ## Enumeration specifying a path component.
@@ -845,6 +845,7 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
var f: WIN32_FIND_DATA
var h = findFirstFile(dir / "*", f)
if h != -1:
defer: findClose(h)
while true:
var k = pcFile
if not skipFindData(f):
@@ -856,10 +857,10 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
else: dir / extractFilename(getFilename(f))
yield (k, xx)
if findNextFile(h, f) == 0'i32: break
findClose(h)
else:
var d = opendir(dir)
if d != nil:
defer: discard closedir(d)
while true:
var x = readdir(d)
if x == nil: break
@@ -883,7 +884,6 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
if S_ISDIR(s.st_mode): k = pcDir
if S_ISLNK(s.st_mode): k = succ(k)
yield (k, y)
discard closedir(d)
iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {.
tags: [ReadDirEffect].} =

View File

@@ -876,7 +876,7 @@ elif not defined(useNimRtl):
let sizeRead = read(data.pErrorPipe[readIdx], addr error, sizeof(error))
if sizeRead == sizeof(error):
raiseOSError("Could not find command: '$1'. OS error: $2" %
[$data.sysCommand, $strerror(error)])
[$data.sysCommand, $strerror(error)])
return pid

View File

@@ -9,7 +9,7 @@
# TODO: Docs.
import os, unsigned, hashes
import os, hashes
when defined(linux):
import posix, epoll
@@ -118,7 +118,7 @@ elif defined(linux):
# are therefore constantly ready. (leading to 100% CPU usage).
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0:
raiseOSError(osLastError())
s.fds.mget(fd).events = events
s.fds[fd].events = events
else:
var event = createEventStruct(events, fd)
if s.fds[fd].events == {}:
@@ -129,7 +129,7 @@ elif defined(linux):
else:
if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0:
raiseOSError(osLastError())
s.fds.mget(fd).events = events
s.fds[fd].events = events
proc unregister*(s: var Selector, fd: SocketHandle) =
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0:
@@ -229,7 +229,7 @@ elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
modifyKQueue(s.kqFD, fd, event, EV_ADD)
for event in previousEvents-events:
modifyKQueue(s.kqFD, fd, event, EV_DELETE)
s.fds.mget(fd).events = events
s.fds[fd].events = events
proc unregister*(s: var Selector, fd: SocketHandle) =
for event in s.fds[fd].events:
@@ -298,7 +298,7 @@ elif not defined(nimdoc):
proc update*(s: var Selector, fd: SocketHandle, events: set[Event]) =
#if not s.fds.hasKey(fd):
# raise newException(ValueError, "File descriptor not found.")
s.fds.mget(fd).events = events
s.fds[fd].events = events
proc unregister*(s: var Selector, fd: SocketHandle) =
s.fds.del(fd)

View File

@@ -2960,9 +2960,9 @@ when not defined(JS): #and not defined(nimscript):
## buffer.add(line.replace("a", "0") & '\x0A')
## writeFile(filename, buffer)
var f = open(filename, bufSize=8000)
defer: close(f)
var res = TaintedString(newStringOfCap(80))
while f.readLine(res): yield res
close(f)
iterator lines*(f: File): TaintedString {.tags: [ReadIOEffect].} =
## Iterate over any line in the file `f`.

View File

@@ -138,7 +138,7 @@ proc slave(w: ptr Worker) {.thread.} =
const NumThreads = 4
var
workers: array[NumThreads, TThread[ptr Worker]]
workers: array[NumThreads, Thread[ptr Worker]]
workersData: array[NumThreads, Worker]
proc setup() =