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

This commit is contained in:
Andreas Rumpf
2016-04-19 12:11:18 +02:00
35 changed files with 590 additions and 176 deletions

View File

@@ -654,7 +654,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
else:
result = cppName & "<"
for i in 1 .. typ.len-2:
if i > 1: result.add(", ")
if i > 1: result.add(" COMMA ")
result.add(getTypeDescAux(m, typ.sons[i], check))
result.add("> ")
# always call for sideeffects:

View File

@@ -129,7 +129,7 @@ proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
result = bindOrCheck(c, p.sons[2].sym, arglist)
proc matches(c: PPatternContext, p, n: PNode): bool =
# hidden conversions (?)
let n = skipHidden(n)
if nfNoRewrite in n.flags:
result = false
elif isPatternParam(c, p):

View File

@@ -414,8 +414,8 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
result = newTransNode(nkChckRange, n, 3)
dest = skipTypes(n.typ, abstractVar)
result[0] = transform(c, n.sons[1])
result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), dest).PTransNode
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), dest).PTransNode
of tyFloat..tyFloat128:
# XXX int64 -> float conversion?
if skipTypes(n.typ, abstractVar).kind == tyRange:

View File

@@ -1448,6 +1448,18 @@ proc skipConv*(n: PNode): PNode =
result = n.sons[1]
else: discard
proc skipHidden*(n: PNode): PNode =
result = n
while true:
case result.kind
of nkHiddenStdConv, nkHiddenSubConv:
if result.sons[1].typ.classify == result.typ.classify:
result = result.sons[1]
else: break
of nkHiddenDeref, nkHiddenAddr:
result = result.sons[0]
else: break
proc skipConvTakeType*(n: PNode): PNode =
result = n.skipConv
result.typ = n.typ

View File

@@ -796,17 +796,17 @@ proc infix*(a: NimNode; op: string;
proc unpackPostfix*(node: NimNode): tuple[node: NimNode; op: string] {.
compileTime.} =
node.expectKind nnkPostfix
result = (node[0], $node[1])
result = (node[1], $node[0])
proc unpackPrefix*(node: NimNode): tuple[node: NimNode; op: string] {.
compileTime.} =
node.expectKind nnkPrefix
result = (node[0], $node[1])
result = (node[1], $node[0])
proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string;
right: NimNode] {.compileTime.} =
assert node.kind == nnkInfix
result = (node[0], $node[1], node[2])
result = (node[1], $node[0], node[2])
proc copy*(node: NimNode): NimNode {.compileTime.} =
## An alias for copyNimTree().

View File

@@ -105,7 +105,8 @@ else:
proc readLineFromStdin*(prompt: string): TaintedString {.
tags: [ReadIOEffect, WriteIOEffect].} =
var buffer = linenoise.readLine(prompt)
if isNil(buffer): quit(0)
if isNil(buffer):
raise newException(IOError, "Linenoise returned nil")
result = TaintedString($buffer)
if result.string.len > 0:
historyAdd(buffer)
@@ -114,12 +115,12 @@ else:
proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {.
tags: [ReadIOEffect, WriteIOEffect].} =
var buffer = linenoise.readLine(prompt)
if isNil(buffer): quit(0)
if isNil(buffer):
raise newException(IOError, "Linenoise returned nil")
line = TaintedString($buffer)
if line.string.len > 0:
historyAdd(buffer)
linenoise.free(buffer)
# XXX how to determine CTRL+D?
result = true
proc readPasswordFromStdin*(prompt: string, password: var TaintedString):

View File

@@ -9,6 +9,9 @@
## This module provides an easy to use sockets-style
## nim interface to the OpenSSL library.
##
## **Warning:** This module is deprecated, use the SSL procedures defined in
## the ``net`` module instead.
{.deprecated.}

View File

@@ -222,6 +222,8 @@ __clang__
/* ----------------------------------------------------------------------- */
#define COMMA ,
#include <limits.h>
#include <stddef.h>

View File

@@ -2627,3 +2627,17 @@ proc utimes*(path: cstring, times: ptr array [2, Timeval]): int {.
## Returns zero on success.
##
## For more information read http://www.unix.com/man-page/posix/3/utimes/.
proc handle_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {.importc: "signal", header: "<signal.h>".}
template onSignal*(signals: varargs[cint], body: untyped): stmt =
## Setup code to be executed when Unix signals are received. Example:
## from posix import SIGINT, SIGTERM
## onSignal(SIGINT, SIGTERM):
## echo "bye"
for s in signals:
handle_signal(s,
proc (sig: cint) {.noconv.} =
body
)

View File

@@ -1316,6 +1316,23 @@ proc generateExceptionCheck(futSym,
)
result.add elseNode
template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver,
rootReceiver: expr, fromNode: NimNode) =
## Params:
## futureVarNode: The NimNode which is a symbol identifying the Future[T]
## variable to yield.
## fromNode: Used for better debug information (to give context).
## valueReceiver: The node which defines an expression that retrieves the
## future's value.
##
## rootReceiver: ??? TODO
# -> yield future<x>
result.add newNimNode(nnkYieldStmt, fromNode).add(futureVarNode)
# -> future<x>.read
valueReceiver = newDotExpr(futureVarNode, newIdentNode("read"))
result.add generateExceptionCheck(futureVarNode, tryStmt, rootReceiver,
fromNode)
template createVar(result: var NimNode, futSymName: string,
asyncProc: NimNode,
valueReceiver, rootReceiver: expr,
@@ -1323,9 +1340,7 @@ template createVar(result: var NimNode, futSymName: string,
result = newNimNode(nnkStmtList, fromNode)
var futSym = genSym(nskVar, "future")
result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
result.add newNimNode(nnkYieldStmt, fromNode).add(futSym) # -> yield future<x>
valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future<x>.read
result.add generateExceptionCheck(futSym, tryStmt, rootReceiver, fromNode)
useVar(result, futSym, valueReceiver, rootReceiver, fromNode)
proc processBody(node, retFutureSym: NimNode,
subTypeIsVoid: bool,
@@ -1352,7 +1367,11 @@ proc processBody(node, retFutureSym: NimNode,
case node[1].kind
of nnkIdent, nnkInfix:
# await x
result = newNimNode(nnkYieldStmt, node).add(node[1]) # -> yield x
result = newNimNode(nnkStmtList, node)
var futureValue: NimNode
result.useVar(node[1], futureValue, futureValue, node)
# -> yield x
# -> x.read()
of nnkCall, nnkCommand:
# await foo(p, x)
var futureValue: NimNode
@@ -1550,6 +1569,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
for i in 0 .. <result[4].len:
if result[4][i].kind == nnkIdent and result[4][i].ident == !"async":
result[4].del(i)
result[4] = newEmptyNode()
if subtypeIsVoid:
# Add discardable pragma.
if returnType.kind == nnkEmpty:
@@ -1559,7 +1579,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
result[6] = outerProcBody
#echo(treeRepr(result))
#if prc[0].getName == "hubConnectionLoop":
#if prc[0].getName == "g":
# echo(toStrLit(result))
macro async*(prc: stmt): stmt {.immediate.} =

View File

@@ -162,7 +162,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
# Request completed immediately.
var bytesRead: DWord
let overlappedRes = getOverlappedResult(f.fd.Handle,
cast[POverlapped](ol)[], bytesRead, false.WinBool)
cast[POverlapped](ol), bytesRead, false.WinBool)
if not overlappedRes.bool:
let err = osLastError()
if err.int32 == ERROR_HANDLE_EOF:
@@ -282,7 +282,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
# Request completed immediately.
var bytesWritten: DWord
let overlappedRes = getOverlappedResult(f.fd.Handle,
cast[POverlapped](ol)[], bytesWritten, false.WinBool)
cast[POverlapped](ol), bytesWritten, false.WinBool)
if not overlappedRes.bool:
retFuture.fail(newException(OSError, osErrorMsg(osLastError())))
else:

View File

@@ -11,7 +11,7 @@
## asynchronous dispatcher defined in the ``asyncdispatch`` module.
##
## SSL
## ---
## ----
##
## SSL can be enabled by compiling with the ``-d:ssl`` flag.
##
@@ -62,7 +62,9 @@ import os
export SOBool
when defined(ssl):
const defineSsl = defined(ssl) or defined(nimdoc)
when defineSsl:
import openssl
type
@@ -79,7 +81,7 @@ type
of false: nil
case isSsl: bool
of true:
when defined(ssl):
when defineSsl:
sslHandle: SslPtr
sslContext: SslContext
bioIn: BIO
@@ -125,7 +127,7 @@ proc newAsyncSocket*(domain, sockType, protocol: cint,
Domain(domain), SockType(sockType),
Protocol(protocol), buffered)
when defined(ssl):
when defineSsl:
proc getSslError(handle: SslPtr, err: cint): cint =
assert err < 0
var ret = SSLGetError(handle, err.cint)
@@ -186,7 +188,7 @@ proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} =
## or an error occurs.
await connect(socket.fd.AsyncFD, address, port, socket.domain)
if socket.isSsl:
when defined(ssl):
when defineSsl:
let flags = {SocketFlag.SafeDisconn}
sslSetConnectState(socket.sslHandle)
sslLoop(socket, flags, sslDoHandshake(socket.sslHandle))
@@ -197,7 +199,7 @@ template readInto(buf: cstring, size: int, socket: AsyncSocket,
## this is a template and not a proc.
var res = 0
if socket.isSsl:
when defined(ssl):
when defineSsl:
# SSL mode.
sslLoop(socket, flags,
sslRead(socket.sslHandle, buf, size.cint))
@@ -274,7 +276,7 @@ proc send*(socket: AsyncSocket, data: string,
## data has been sent.
assert socket != nil
if socket.isSsl:
when defined(ssl):
when defineSsl:
var copy = data
sslLoop(socket, flags,
sslWrite(socket.sslHandle, addr copy[0], copy.len.cint))
@@ -426,9 +428,6 @@ proc recvLine*(socket: AsyncSocket,
##
## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol
## uses ``\r\L`` to delimit a new line.
template addNLIfEmpty(): stmt =
if result.len == 0:
result.add("\c\L")
assert SocketFlag.Peek notin flags ## TODO:
# TODO: Optimise this
@@ -456,7 +455,8 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {.
of AF_INET6: realaddr = "::"
of AF_INET: realaddr = "0.0.0.0"
else:
raiseOSError("Unknown socket address family and no address specified to bindAddr")
raise newException(ValueError,
"Unknown socket address family and no address specified to bindAddr")
var aiList = getAddrInfo(realaddr, port, socket.domain)
if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
@@ -468,7 +468,7 @@ proc close*(socket: AsyncSocket) =
## Closes the socket.
defer:
socket.fd.AsyncFD.closeSocket()
when defined(ssl):
when defineSsl:
if socket.isSSL:
let res = SslShutdown(socket.sslHandle)
SSLFree(socket.sslHandle)
@@ -478,7 +478,7 @@ proc close*(socket: AsyncSocket) =
raiseSslError()
socket.closed = true # TODO: Add extra debugging checks for this.
when defined(ssl):
when defineSsl:
proc wrapSocket*(ctx: SslContext, socket: AsyncSocket) =
## Wraps a socket in an SSL context. This function effectively turns
## ``socket`` into an SSL socket.

View File

@@ -90,6 +90,8 @@ template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediat
if r+4 != result.len:
setLen(result, r+4)
else:
if r != result.len:
setLen(result, r)
#assert(r == result.len)
discard
@@ -162,4 +164,3 @@ when isMainModule:
"asure.", longText]
for t in items(tests):
assert decode(encode(t)) == t

View File

@@ -663,6 +663,27 @@ proc sort*[A, B](t: OrderedTableRef[A, B],
## contrast to the `sort` for count tables).
t[].sort(cmp)
proc del*[A, B](t: var OrderedTable[A, B], key: A) =
## deletes `key` from ordered hash table `t`. O(n) comlexity.
var prev = -1
let hc = hash(key)
forAllOrderedPairs:
if t.data[h].hcode == hc:
if t.first == h:
t.first = t.data[h].next
else:
t.data[prev].next = t.data[h].next
var zeroValue : type(t.data[h])
t.data[h] = zeroValue
dec t.counter
break
else:
prev = h
proc del*[A, B](t: var OrderedTableRef[A, B], key: A) =
## deletes `key` from ordered hash table `t`. O(n) comlexity.
t[].del(key)
# ------------------------------ count tables -------------------------------
type
@@ -984,6 +1005,26 @@ when isMainModule:
s3[p1] = 30_000
s3[p2] = 45_000
block: # Ordered table should preserve order after deletion
var
s4 = initOrderedTable[int, int]()
s4[1] = 1
s4[2] = 2
s4[3] = 3
var prev = 0
for i in s4.values:
doAssert(prev < i)
prev = i
s4.del(2)
doAssert(2 notin s4)
doAssert(s4.len == 2)
prev = 0
for i in s4.values:
doAssert(prev < i)
prev = i
var
t1 = initCountTable[string]()
t2 = initCountTable[string]()

View File

@@ -335,7 +335,7 @@ proc addFiles*(p: var MultipartData, xs: openarray[tuple[name, file: string]]):
var m = newMimetypes()
for name, file in xs.items:
var contentType: string
let (dir, fName, ext) = splitFile(file)
let (_, fName, ext) = splitFile(file)
if ext.len > 0:
contentType = m.getMimetype(ext[1..ext.high], nil)
p.add(name, readFile(file), fName & ext, contentType)
@@ -627,7 +627,7 @@ proc newAsyncHttpClient*(userAgent = defUserAgent,
result.userAgent = defUserAgent
result.maxRedirects = maxRedirects
when defined(ssl):
result.sslContext = net.SslContext(sslContext)
result.sslContext = sslContext
proc close*(client: AsyncHttpClient) =
## Closes any connections held by the HTTP client.

View File

@@ -56,6 +56,11 @@ import
export
tables.`$`
when defined(nimJsonGet):
{.pragma: deprecatedGet, deprecated.}
else:
{.pragma: deprecatedGet.}
type
JsonEventKind* = enum ## enumeration of all events that may occur when parsing
jsonError, ## an error occurred during parsing
@@ -799,16 +804,23 @@ proc len*(n: JsonNode): int =
of JObject: result = n.fields.len
else: discard
proc `[]`*(node: JsonNode, name: string): JsonNode {.inline.} =
proc `[]`*(node: JsonNode, name: string): JsonNode {.inline, deprecatedGet.} =
## Gets a field from a `JObject`, which must not be nil.
## If the value at `name` does not exist, returns nil
## If the value at `name` does not exist, raises KeyError.
##
## **Note:** The behaviour of this procedure changed in version 0.14.0. To
## get a list of usages and to restore the old behaviour of this procedure,
## compile with the ``-d:nimJsonGet`` flag.
assert(not isNil(node))
assert(node.kind == JObject)
result = node.fields.getOrDefault(name)
when defined(nimJsonGet):
if not node.fields.hasKey(name): return nil
result = node.fields[name]
proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} =
## Gets the node at `index` in an Array. Result is undefined if `index`
## is out of bounds
## is out of bounds, but as long as array bound checks are enabled it will
## result in an exception.
assert(not isNil(node))
assert(node.kind == JArray)
return node.elems[index]
@@ -838,20 +850,28 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
## Traverses the node and gets the given value. If any of the
## keys do not exist, returns nil. Also returns nil if one of the
## intermediate data structures is not an object
## keys do not exist, returns ``nil``. Also returns ``nil`` if one of the
## intermediate data structures is not an object.
result = node
for key in keys:
if isNil(result) or result.kind!=JObject:
if isNil(result) or result.kind != JObject:
return nil
result=result[key]
result = result.fields.getOrDefault(key)
proc getOrDefault*(node: JsonNode, key: string): JsonNode =
## Gets a field from a `node`. If `node` is nil or not an object or
## value at `key` does not exist, returns nil
if not isNil(node) and node.kind == JObject:
result = node.fields.getOrDefault(key)
template simpleGetOrDefault*{`{}`(node, [key])}(node: JsonNode, key: string): JsonNode = node.getOrDefault(key)
proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
## Traverses the node and tries to set the value at the given location
## to `value` If any of the keys are missing, they are added
## to ``value``. If any of the keys are missing, they are added.
var node = node
for i in 0..(keys.len-2):
if isNil(node[keys[i]]):
if not node.hasKey(keys[i]):
node[keys[i]] = newJObject()
node = node[keys[i]]
node[keys[keys.len-1]] = value
@@ -1217,16 +1237,6 @@ when false:
# To get that we shall use, obj["json"]
when isMainModule:
when not defined(js):
var parsed = parseFile("tests/testdata/jsontest.json")
try:
discard parsed["key2"][12123]
doAssert(false)
except IndexError: doAssert(true)
var parsed2 = parseFile("tests/testdata/jsontest2.json")
doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}"""
# nil passthrough
@@ -1314,3 +1324,19 @@ when isMainModule:
var j4 = %*{"test": nil}
doAssert j4 == %{"test": newJNull()}
echo("99% of tests finished. Going to try loading file.")
# Test loading of file.
when not defined(js):
var parsed = parseFile("tests/testdata/jsontest.json")
try:
discard parsed["key2"][12123]
doAssert(false)
except IndexError: doAssert(true)
var parsed2 = parseFile("tests/testdata/jsontest2.json")
doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
echo("Tests succeeded!")

View File

@@ -8,6 +8,10 @@
#
## This module contains various string matchers for email addresses, etc.
##
## **Warning:** This module is deprecated since version 0.14.0.
{.deprecated.}
{.deadCodeElim: on.}
{.push debugger:off .} # the user does not want to trace a part

View File

@@ -8,19 +8,76 @@
#
## This module implements a high-level cross-platform sockets interface.
## The procedures implemented in this module are primarily for blocking sockets.
## For asynchronous non-blocking sockets use the ``asyncnet`` module together
## with the ``asyncdispatch`` module.
##
## The first thing you will always need to do in order to start using sockets,
## is to create a new instance of the ``Socket`` type using the ``newSocket``
## procedure.
##
## SSL
## ====
##
## In order to use the SSL procedures defined in this module, you will need to
## compile your application with the ``-d:ssl`` flag.
##
## Examples
## ========
##
## Connecting to a server
## ----------------------
##
## After you create a socket with the ``newSocket`` procedure, you can easily
## connect it to a server running at a known hostname (or IP address) and port.
## To do so over TCP, use the example below.
##
## .. code-block:: Nim
## var socket = newSocket()
## socket.connect("google.com", Port(80))
##
## UDP is a connectionless protocol, so UDP sockets don't have to explicitly
## call the ``connect`` procedure. They can simply start sending data
## immediately.
##
## .. code-block:: Nim
## var socket = newSocket()
## socket.sendTo("192.168.0.1", Port(27960), "status\n")
##
## Creating a server
## -----------------
##
## After you create a socket with the ``newSocket`` procedure, you can create a
## TCP server by calling the ``bindAddr`` and ``listen`` procedures.
##
## .. code-block:: Nim
## var socket = newSocket()
## socket.bindAddr(Port(1234))
## socket.listen()
##
## You can then begin accepting connections using the ``accept`` procedure.
##
## .. code-block:: Nim
## var client = newSocket()
## var address = ""
## while true:
## socket.acceptAddr(client, address)
## echo("Client connected from: ", address)
##
{.deadCodeElim: on.}
import nativesockets, os, strutils, parseutils, times
export Port, `$`, `==`
const useWinVersion = defined(Windows) or defined(nimdoc)
const defineSsl = defined(ssl) or defined(nimdoc)
when defined(ssl):
when defineSsl:
import openssl
# Note: The enumerations are mapped to Window's constants.
when defined(ssl):
when defineSsl:
type
SslError* = object of Exception
@@ -54,7 +111,7 @@ type
currPos: int # current index in buffer
bufLen: int # current length of buffer
of false: nil
when defined(ssl):
when defineSsl:
case isSsl: bool
of true:
sslHandle: SSLPtr
@@ -160,7 +217,7 @@ proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
raiseOSError(osLastError())
result = newSocket(fd, domain, sockType, protocol, buffered)
when defined(ssl):
when defineSsl:
CRYPTO_malloc_init()
SslLibraryInit()
SslLoadErrorStrings()
@@ -301,7 +358,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false,
## error was caused by no data being available to be read.
##
## If ``err`` is not lower than 0 no exception will be raised.
when defined(ssl):
when defineSsl:
if socket.isSSL:
if err <= 0:
var ret = SSLGetError(socket.sslHandle, err.cint)
@@ -334,7 +391,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false,
raiseSSLError()
else: raiseSSLError("Unknown Error")
if err == -1 and not (when defined(ssl): socket.isSSL else: false):
if err == -1 and not (when defineSsl: socket.isSSL else: false):
var lastE = if lastError.int == -1: getSocketError(socket) else: lastError
if async:
when useWinVersion:
@@ -414,7 +471,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
client.isBuffered = server.isBuffered
# Handle SSL.
when defined(ssl):
when defineSsl:
if server.isSSL:
# We must wrap the client sock in a ssl context.
@@ -425,7 +482,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
# Client socket is set above.
address = $inet_ntoa(sockAddress.sin_addr)
when false: #defined(ssl):
when false: #defineSsl:
proc acceptAddrSSL*(server: Socket, client: var Socket,
address: var string): SSLAcceptResult {.
tags: [ReadIOEffect].} =
@@ -444,7 +501,7 @@ when false: #defined(ssl):
## ``AcceptNoClient`` will be returned when no client is currently attempting
## to connect.
template doHandshake(): stmt =
when defined(ssl):
when defineSsl:
if server.isSSL:
client.setBlocking(false)
# We must wrap the client sock in a ssl context.
@@ -495,7 +552,7 @@ proc accept*(server: Socket, client: var Socket,
proc close*(socket: Socket) =
## Closes a socket.
try:
when defined(ssl):
when defineSsl:
if socket.isSSL:
ErrClearError()
# As we are closing the underlying socket immediately afterwards,
@@ -547,8 +604,9 @@ 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)
when defined(ssl):
proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} =
when defineSsl:
proc handshake*(socket: Socket): bool
{.tags: [ReadIOEffect, WriteIOEffect], deprecated.} =
## This proc needs to be called on a socket after it connects. This is
## only applicable when using ``connectAsync``.
## This proc performs the SSL handshake.
@@ -557,6 +615,8 @@ when defined(ssl):
## ``True`` whenever handshake completed successfully.
##
## A ESSL error is raised on any other errors.
##
## **Note:** This procedure is deprecated since version 0.14.0.
result = true
if socket.isSSL:
var ret = SSLConnect(socket.sslHandle)
@@ -594,7 +654,7 @@ proc hasDataBuffered*(s: Socket): bool =
if s.isBuffered:
result = s.bufLen > 0 and s.currPos != s.bufLen
when defined(ssl):
when defineSsl:
if s.isSSL and not result:
result = s.sslHasPeekChar
@@ -608,7 +668,7 @@ proc select(readfd: Socket, timeout = 500): int =
proc readIntoBuf(socket: Socket, flags: int32): int =
result = 0
when defined(ssl):
when defineSsl:
if socket.isSSL:
result = SSLRead(socket.sslHandle, addr(socket.buffer), int(socket.buffer.high))
else:
@@ -658,7 +718,7 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect]
result = read
else:
when defined(ssl):
when defineSsl:
if socket.isSSL:
if socket.sslHasPeekChar:
copyMem(data, addr(socket.sslPeekChar), 1)
@@ -696,7 +756,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int,
if timeout - int(waited * 1000.0) < 1:
raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
when defined(ssl):
when defineSsl:
if socket.isSSL:
if socket.hasDataBuffered:
# sslPeekChar is present.
@@ -764,7 +824,7 @@ proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
c = socket.buffer[socket.currPos]
else:
when defined(ssl):
when defineSsl:
if socket.isSSL:
if not socket.sslHasPeekChar:
result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1)
@@ -872,7 +932,7 @@ proc send*(socket: Socket, data: pointer, size: int): int {.
##
## **Note**: This is a low-level version of ``send``. You likely should use
## the version below.
when defined(ssl):
when defineSsl:
if socket.isSSL:
return SSLWrite(socket.sslHandle, cast[cstring](data), size)
@@ -943,7 +1003,7 @@ proc sendTo*(socket: Socket, address: string, port: Port,
proc isSsl*(socket: Socket): bool =
## Determines whether ``socket`` is a SSL socket.
when defined(ssl):
when defineSsl:
result = socket.isSSL
else:
result = false
@@ -1253,7 +1313,7 @@ proc connect*(socket: Socket, address: string,
dealloc(aiList)
if not success: raiseOSError(lastError)
when defined(ssl):
when defineSsl:
if socket.isSSL:
# RFC3546 for SNI specifies that IP addresses are not allowed.
if not isIpAddress(address):
@@ -1314,8 +1374,10 @@ proc connect*(socket: Socket, address: string, port = Port(0),
if selectWrite(s, timeout) != 1:
raise newException(TimeoutError, "Call to 'connect' timed out.")
else:
when defined(ssl):
when defineSsl:
if socket.isSSL:
socket.fd.setBlocking(true)
{.warning[Deprecated]: off.}
doAssert socket.handshake()
{.warning[Deprecated]: on.}
socket.fd.setBlocking(true)

View File

@@ -129,7 +129,7 @@ proc raiseOSError*(errorCode: OSErrorCode; additionalInfo = "") {.noinline.} =
if additionalInfo.len == 0:
e.msg = osErrorMsg(errorCode)
else:
e.msg = additionalInfo & " " & osErrorMsg(errorCode)
e.msg = osErrorMsg(errorCode) & "\nAdditional info: " & additionalInfo
if e.msg == "":
e.msg = "unknown OS error"
raise e
@@ -1452,7 +1452,7 @@ template rawToFormalFileInfo(rawInfo, formalInfo): expr =
## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows,
## or a 'Stat' structure on posix
when defined(Windows):
template toTime(e): expr = winTimeToUnixTime(rdFileTime(e))
template toTime(e: FILETIME): expr {.gensym.} = winTimeToUnixTime(rdFileTime(e)) # local templates default to bind semantics
template merge(a, b): expr = a or (b shl 32)
formalInfo.id.device = rawInfo.dwVolumeSerialNumber
formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)

View File

@@ -784,8 +784,7 @@ proc indent*(s: string, count: Natural, padding: string = " "): string
{.noSideEffect, rtl, extern: "nsuIndent".} =
## Indents each line in ``s`` by ``count`` amount of ``padding``.
##
## **Note:** This currently does not preserve the specific new line characters
## used.
## **Note:** This does not preserve the new line characters used in ``s``.
result = ""
var i = 0
for line in s.splitLines():
@@ -796,32 +795,39 @@ proc indent*(s: string, count: Natural, padding: string = " "): string
result.add(line)
i.inc
proc unindent*(s: string, eatAllIndent = false): string {.
noSideEffect, rtl, extern: "nsuUnindent".} =
## Unindents `s`.
result = newStringOfCap(s.len)
proc unindent*(s: string, count: Natural, padding: string = " "): string
{.noSideEffect, rtl, extern: "nsuUnindent".} =
## Unindents each line in ``s`` by ``count`` amount of ``padding``.
##
## **Note:** This does not preserve the new line characters used in ``s``.
result = ""
var i = 0
var pattern = true
var indent = 0
while s[i] == ' ': inc i
var level = if i == 0: -1 else: i
while i < s.len:
if s[i] == ' ':
if i > 0 and s[i-1] in {'\l', '\c'}:
pattern = true
indent = 0
if pattern:
inc(indent)
if indent > level and not eatAllIndent:
result.add(s[i])
if level < 0: level = indent
else:
# a space somewhere: do not delete
result.add(s[i])
else:
pattern = false
result.add(s[i])
inc i
for line in s.splitLines():
if i != 0:
result.add("\n")
var indentCount = 0
for j in 0..<count.int:
indentCount.inc
if line[j .. j + <padding.len] != padding:
indentCount = j
break
result.add(line[indentCount*padding.len .. ^1])
i.inc
proc unindent*(s: string): string
{.noSideEffect, rtl, extern: "nsuUnindentAll".} =
## Removes all indentation composed of whitespace from each line in ``s``.
##
## For example:
##
## .. code-block:: nim
## const x = """
## Hello
## There
## """.unindent()
##
## doAssert x == "Hello\nThere\n"
unindent(s, 1000) # TODO: Passing a 1000 is a bit hackish.
proc startsWith*(s, prefix: string): bool {.noSideEffect,
rtl, extern: "nsuStartsWith".} =
@@ -1743,3 +1749,33 @@ when isMainModule:
doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
doAssert join([1, 2, 3]) == "123"
doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
doAssert """~~!!foo
~~!!bar
~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz"
doAssert """~~!!foo
~~!!bar
~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz"
doAssert """~~foo
~~ bar
~~ baz""".unindent(4, "~") == "foo\n bar\n baz"
doAssert """foo
bar
baz
""".unindent(4) == "foo\nbar\nbaz\n"
doAssert """foo
bar
baz
""".unindent(2) == "foo\n bar\n baz\n"
doAssert """foo
bar
baz
""".unindent(100) == "foo\nbar\nbaz\n"
doAssert """foo
foo
bar
""".unindent() == "foo\nfoo\nbar\n"
echo("strutils tests passed")

View File

@@ -390,11 +390,11 @@ when isMainModule:
doAssert(("type MyEnum* = enum\n $', '2i'\n '{..}" % ["fieldA",
"fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"]).replace(" \n", "\n") ==
strutils.unindent """
strutils.unindent("""
type MyEnum* = enum
fieldA, fieldB,
FiledClkad, fieldD,
fieldE, longishFieldName""")
fieldE, longishFieldName""", 6))
doAssert subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
@@ -404,8 +404,8 @@ when isMainModule:
doAssert((subex("type\n Enum = enum\n $', '40c'\n '{..}") % [
"fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]).replace(" \n", "\n") ==
strutils.unindent """
strutils.unindent("""
type
Enum = enum
fieldNameA, fieldNameB, fieldNameC,
fieldNameD""")
fieldNameD""", 6))

View File

@@ -182,7 +182,16 @@ proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.}
## converts the calendar time `t` to broken-down time representation,
## expressed in Coordinated Universal Time (UTC).
proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign.}
proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign, deprecated.}
## converts a broken-down time structure to
## calendar time representation. The function ignores the specified
## contents of the structure members `weekday` and `yearday` and recomputes
## them from the other information in the broken-down time structure.
##
## **Warning:** This procedure is deprecated since version 0.14.0.
## Use ``toTime`` instead.
proc toTime*(timeInfo: TimeInfo): Time {.tags: [], benign.}
## converts a broken-down time structure to
## calendar time representation. The function ignores the specified
## contents of the structure members `weekday` and `yearday` and recomputes
@@ -356,7 +365,7 @@ proc `+`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
##
## **Note:** This has been only briefly tested and it may not be
## very accurate.
let t = toSeconds(timeInfoToTime(a))
let t = toSeconds(toTime(a))
let secs = toSeconds(a, interval)
result = getLocalTime(fromSeconds(t + secs))
@@ -365,7 +374,7 @@ proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
##
## **Note:** This has been only briefly tested, it is inaccurate especially
## when you subtract so much that you reach the Julian calendar.
let t = toSeconds(timeInfoToTime(a))
let t = toSeconds(toTime(a))
var intval: TimeInterval
intval.milliseconds = - interval.milliseconds
intval.seconds = - interval.seconds
@@ -517,6 +526,11 @@ when not defined(JS):
# because the header of mktime is broken in my version of libc
return mktime(timeInfoToTM(cTimeInfo))
proc toTime(timeInfo: TimeInfo): Time =
var cTimeInfo = timeInfo # for C++ we have to make a copy,
# because the header of mktime is broken in my version of libc
return mktime(timeInfoToTM(cTimeInfo))
proc toStringTillNL(p: cstring): string =
result = ""
var i = 0
@@ -618,7 +632,16 @@ elif defined(JS):
result.setFullYear(timeInfo.year)
result.setDate(timeInfo.monthday)
proc `$`(timeInfo: TimeInfo): string = return $(timeInfoToTime(timeInfo))
proc toTime*(timeInfo: TimeInfo): Time =
result = internGetTime()
result.setSeconds(timeInfo.second)
result.setMinutes(timeInfo.minute)
result.setHours(timeInfo.hour)
result.setMonth(ord(timeInfo.month))
result.setFullYear(timeInfo.year)
result.setDate(timeInfo.monthday)
proc `$`(timeInfo: TimeInfo): string = return $(toTime(timeInfo))
proc `$`(time: Time): string = return $time.toLocaleString()
proc `-` (a, b: Time): int64 =
@@ -708,24 +731,24 @@ proc years*(y: int): TimeInterval {.inline.} =
proc `+=`*(t: var Time, ti: TimeInterval) =
## modifies `t` by adding the interval `ti`
t = timeInfoToTime(getLocalTime(t) + ti)
t = toTime(getLocalTime(t) + ti)
proc `+`*(t: Time, ti: TimeInterval): Time =
## adds the interval `ti` to Time `t`
## by converting to localTime, adding the interval, and converting back
##
## ``echo getTime() + 1.day``
result = timeInfoToTime(getLocalTime(t) + ti)
result = toTime(getLocalTime(t) + ti)
proc `-=`*(t: var Time, ti: TimeInterval) =
## modifies `t` by subtracting the interval `ti`
t = timeInfoToTime(getLocalTime(t) - ti)
t = toTime(getLocalTime(t) - ti)
proc `-`*(t: Time, ti: TimeInterval): Time =
## adds the interval `ti` to Time `t`
##
## ``echo getTime() - 1.day``
result = timeInfoToTime(getLocalTime(t) - ti)
result = toTime(getLocalTime(t) - ti)
proc formatToken(info: TimeInfo, token: string, buf: var string) =
## Helper of the format proc to parse individual tokens.
@@ -1193,7 +1216,7 @@ proc parse*(value, layout: string): TimeInfo =
parseToken(info, token, value, j)
token = ""
# Reset weekday as it might not have been provided and the default may be wrong
info.weekday = getLocalTime(timeInfoToTime(info)).weekday
info.weekday = getLocalTime(toTime(info)).weekday
return info
# Leap year calculations are adapted from:
@@ -1204,7 +1227,7 @@ proc parse*(value, layout: string): TimeInfo =
proc countLeapYears*(yearSpan: int): int =
## Returns the number of leap years spanned by a given number of years.
##
## Note: for leap years, start date is assumed to be 1 AD.
## **Note:** For leap years, start date is assumed to be 1 AD.
## counts the number of leap years up to January 1st of a given year.
## Keep in mind that if specified year is a leap year, the leap day
## has not happened before January 1st of that year.
@@ -1239,13 +1262,14 @@ proc getDayOfWeek*(day, month, year: int): WeekDay =
y = year - a
m = month + (12*a) - 2
d = (day + y + (y div 4) - (y div 100) + (y div 400) + (31*m) div 12) mod 7
# The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc. so we must correct
# for the WeekDay type.
# The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc.
# so we must correct for the WeekDay type.
if d == 0: return dSun
result = (d-1).WeekDay
proc getDayOfWeekJulian*(day, month, year: int): WeekDay =
## Returns the day of the week enum from day, month and year, according to the Julian calendar.
## Returns the day of the week enum from day, month and year,
## according to the Julian calendar.
# Day & month start from one.
let
a = (14 - month) div 12
@@ -1254,8 +1278,11 @@ proc getDayOfWeekJulian*(day, month, year: int): WeekDay =
d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7
result = d.WeekDay
proc timeToTimeInfo*(t: Time): TimeInfo =
proc timeToTimeInfo*(t: Time): TimeInfo {.deprecated.} =
## Converts a Time to TimeInfo.
##
## **Warning:** This procedure is deprecated since version 0.14.0.
## Use ``getLocalTime`` or ``getGMTime`` instead.
let
secs = t.toSeconds().int
daysSinceEpoch = secs div secondsInDay
@@ -1286,34 +1313,21 @@ proc timeToTimeInfo*(t: Time): TimeInfo =
s = daySeconds mod secondsInMin
result = TimeInfo(year: y, yearday: yd, month: m, monthday: md, weekday: wd, hour: h, minute: mi, second: s)
proc timeToTimeInterval*(t: Time): TimeInterval =
proc timeToTimeInterval*(t: Time): TimeInterval {.deprecated.} =
## Converts a Time to a TimeInterval.
let
secs = t.toSeconds().int
daysSinceEpoch = secs div secondsInDay
(yearsSinceEpoch, daysRemaining) = countYearsAndDays(daysSinceEpoch)
daySeconds = secs mod secondsInDay
result.years = yearsSinceEpoch + epochStartYear
var
mon = mJan
days = daysRemaining
daysInMonth = getDaysInMonth(mon, result.years)
# calculate month and day remainder
while days > daysInMonth and mon <= mDec:
days -= daysInMonth
mon.inc
daysInMonth = getDaysInMonth(mon, result.years)
result.months = mon.int + 1 # month is 1 indexed int
result.days = days
result.hours = daySeconds div secondsInHour + 1
result.minutes = (daySeconds mod secondsInHour) div secondsInMin
result.seconds = daySeconds mod secondsInMin
##
## **Warning:** This procedure is deprecated since version 0.14.0.
## Use ``toTimeInterval`` instead.
# Milliseconds not available from Time
var tInfo = t.getLocalTime()
initInterval(0, tInfo.second, tInfo.minute, tInfo.hour, tInfo.weekday.ord, tInfo.month.ord, tInfo.year)
proc toTimeInterval*(t: Time): TimeInterval =
## Converts a Time to a TimeInterval.
# Milliseconds not available from Time
var tInfo = t.getLocalTime()
initInterval(0, tInfo.second, tInfo.minute, tInfo.hour, tInfo.weekday.ord, tInfo.month.ord, tInfo.year)
when isMainModule:
# this is testing non-exported function

View File

@@ -28,6 +28,9 @@ template mulThreshold(x): expr {.immediate.} = x * 2
when defined(memProfiler):
proc nimProfile(requestedSize: int)
when hasThreadSupport:
import sharedlist
type
WalkOp = enum

View File

@@ -769,7 +769,7 @@ proc getQueuedCompletionStatus*(CompletionPort: Handle,
dwMilliseconds: DWORD): WINBOOL{.stdcall,
dynlib: "kernel32", importc: "GetQueuedCompletionStatus".}
proc getOverlappedResult*(hFile: Handle, lpOverlapped: OVERLAPPED,
proc getOverlappedResult*(hFile: Handle, lpOverlapped: POVERLAPPED,
lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".}

View File

@@ -260,7 +260,7 @@ proc OpenSSL_add_all_algorithms*(){.cdecl, dynlib: DLLUtilName, importc: "OPENSS
proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.}
when not useWinVersion:
when not useWinVersion and not defined(macosx):
proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl,
dynlib: DLLUtilName, importc.}
@@ -532,7 +532,7 @@ proc md5_File* (file: string): string {.raises: [IOError,Exception].} =
result = hexStr(buf)
proc md5_Str* (str:string): string {.raises:[IOError].} =
proc md5_Str*(str:string): string =
##Generate MD5 hash for a string. Result is a 32 character
#hex string with lowercase characters
var

104
readme.md
View File

@@ -1,18 +1,9 @@
# Nim Compiler
[![Join the Chat at irc.freenode.net#nim](https://img.shields.io/badge/IRC-join_chat_in_%23nim-blue.svg)](https://webchat.freenode.net/?channels=nim)
[![Get help](https://img.shields.io/badge/Forum-get%20help-4eb899.svg)](http://forum.nim-lang.org)
[![Stackoverflow](https://img.shields.io/badge/stackoverflow-use_%23nim_tag-yellow.svg)](http://stackoverflow.com/questions/tagged/nim?sort=newest&pageSize=15)
[![Follow @nim_lang!](https://img.shields.io/twitter/follow/nim_lang.svg?style=social)](https://twitter.com/nim_lang)
[![Travis](https://img.shields.io/travis/nim-lang/Nim.svg)](https://travis-ci.org/nim-lang/Nim)
[![Contribute to Nim via Gratipay!](https://img.shields.io/gratipay/team/nim.svg)](https://gratipay.com/nim/)
[![Bountysource](https://img.shields.io/bountysource/team/nim/activity.svg)](https://www.bountysource.com/teams/nim)
# <img src="https://raw.githubusercontent.com/nim-lang/assets/master/Art/logo-crown.png" width="36"> Nim [![Build Status](https://travis-ci.org/nim-lang/Nim.svg?branch=devel)](https://travis-ci.org/nim-lang/Nim)
This repo contains the Nim compiler, Nim's stdlib, tools and
documentation.
documentation. For more information about Nim, including downloads
and documentation for the latest release, check out
[Nim's website](http://nim-lang.org).
## Compiling
Compiling the Nim compiler is quite straightforward. Because
@@ -48,14 +39,15 @@ $ bin/nim c koch
$ ./koch boot -d:release
```
``koch install [dir]`` may then be used to install Nim, but lots of things
don't work then so don't do that. Add it to your PATH instead. More ``koch``
related options are documented in [doc/koch.txt](doc/koch.txt).
You should then add the ``bin`` directory to your PATH, to make it easily
executable on your system.
The above steps can be performed on Windows in a similar fashion, the
``build.bat`` and ``build64.bat`` (for x86_64 systems) are provided to be used
instead of ``build.sh``.
The ``koch`` tool is the Nim build tool, more ``koch`` related options are
documented in [doc/koch.txt](doc/koch.txt).
## Nimble
[Nimble](https://github.com/nim-lang/nimble) is Nim's package manager. For the
@@ -66,12 +58,80 @@ the easiest way of installing Nimble is via:
$ nim e install_nimble.nims
```
## Getting help
A [forum](http://forum.nim-lang.org/) is available if you have any
questions, and you can also get help in the IRC channel on
[Freenode](irc://irc.freenode.net/nim) in #nim. If you ask questions on
[StackOverflow use the nim
tag](http://stackoverflow.com/questions/tagged/nim).
**Warning:** If you install Nimble this way, you will not be able to use binary
Nimble packages or update Nimble easily.
The [Nimble readme](https://github.com/nim-lang/nimble#installation)
provides thorough instructions on how to install Nimble, so that this isn't a
problem.
## Community
[![Join the Chat at irc.freenode.net#nim](https://img.shields.io/badge/IRC-join_chat_in_%23nim-blue.svg)](https://webchat.freenode.net/?channels=nim)
[![Get help](https://img.shields.io/badge/Forum-get%20help-4eb899.svg)](http://forum.nim-lang.org)
[![Stackoverflow](https://img.shields.io/badge/stackoverflow-use_%23nim_tag-yellow.svg)](http://stackoverflow.com/questions/tagged/nim?sort=newest&pageSize=15)
[![Follow @nim_lang!](https://img.shields.io/twitter/follow/nim_lang.svg?style=social)](https://twitter.com/nim_lang)
* The [forum](http://forum.nim-lang.org/) - the best place to ask questions and to discuss Nim.
* [IRC (Freenode#nim)](https://webchat.freenode.net/?channels=nim) - the best place to discuss
Nim in real-time, this is also where most development decision get made!
* [Stackoverflow](http://stackoverflow.com/questions/tagged/nim)
## Contributing
[![Contribute to Nim via Gratipay!](https://img.shields.io/gratipay/team/nim.svg)](https://gratipay.com/nim/)
[![Bountysource](https://img.shields.io/bountysource/team/nim/activity.svg)](https://www.bountysource.com/teams/nim)
We welcome everyone's contributions to Nim. No matter how small or large
the contribution is, anything from small spelling fixes to large modules
intended to be included in the standard library are accepted. Before
you get started, you should know the following about this repositories
structure:
* ``bin/``, ``build/`` - these directories are empty, but are used when Nim is built.
* ``compiler/`` - the compiler source code, all the Nim source code files in this
directory implement the compiler. This also includes nimfix, and plugins
which live in ``compiler/nimfix`` and ``compiler/plugins``
respectively. Nimsuggest used to live in the ``compiler`` directory also,
but was moved to https://github.com/nim-lang/nimsuggest.
* ``config/`` - the configuration for the compiler and documentation generator.
* ``doc/`` - the documentation files in reStructuredText format.
* ``lib/`` - where the standard library lives.
* ``pure/`` - modules in the standard library written in pure Nim.
* ``impure/`` - modules in the standard library written in pure Nim which
depend on libraries written in other languages.
* ``wrappers/`` - modules which wrap libraries written in other languages.
* ``tests/`` - contains tests for the compiler and standard library, organised by
category.
* ``tools/`` - the tools including ``niminst`` and ``nimweb``, most of these are invoked
via ``koch``.
* ``web/`` - the Nim website (http://nim-lang.org).
* ``koch.nim`` - tool used to bootstrap Nim, generate C sources, build the website, documentation
and more.
Most importantly, the ``koch`` tool can be used to run the test suite. To do so compile it first
by executing ``nim c koch``, then execute ``./koch tests``. The test suite takes a while to run,
but you can run specific tests by specifying a category to run, for example ``./koch tests cat async``.
Make sure that the tests all pass before
[submitting your pull request](https://help.github.com/articles/using-pull-requests/).
If you're short on time, you can
just run the tests specific to your change. Just run the category which corresponds to the change
you've made. When you create your pull request, Travis CI will verify that all the tests pass
anyway.
If you're looking for things to do, take a look at our
[issue tracker](https://github.com/nim-lang/Nim/issues). There is always plenty of issues
labelled [``Easy``](https://github.com/nim-lang/Nim/labels/Easy), these should be a good
starting point if this is your first contribution to Nim.
You can also help with the development of Nim by making donations. You can do so
in many ways:
* [Gratipay](https://gratipay.com/nim/)
* [Bountysource](https://www.bountysource.com/teams/nim)
* Bitcoin - 1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ
Finally, if you have any questions feel free to submit a question on the issue tracker,
on the [Nim forum](http://forum.nim-lang.org), or on IRC.
## License
The compiler and the standard library are licensed under the MIT license,

View File

@@ -24,7 +24,7 @@ proc main() {.async.} =
var file = openAsync(fn, fmAppend)
await file.write("\ntest2")
let errorTest = file.readAll()
await errorTest
echo await errorTest
doAssert errorTest.failed
file.close()
file = openAsync(fn, fmRead)

View File

@@ -0,0 +1,9 @@
type
Map {.importcpp: "std::map", header: "<map>".} [T,U] = object
proc cInitMap(T: typedesc, U: typedesc): Map[T,U] {.importcpp: "std::map<'*1,'*2>()", nodecl.}
proc initMap[T, U](): Map[T, U] =
result = cInitMap(T, U)
var x: Map[cstring, cint] = initMap[cstring, cint]()

51
tests/js/tclosures.nim Normal file
View File

@@ -0,0 +1,51 @@
discard """
action: run
"""
import math, strutils
const consolePrefix = "jsCallbacks"
asm """
var callback = []
function regCallback (fn) { callback.push (fn); }
function runCallbacks () {
var result = "\n"
var n = 0
for (var fn in callback) {
n += 1
result += "("+String (n)+")"
result += callback [fn] ()
result += "\n"
}
return result
}
function print (text) { console.log (text); }
"""
proc consoleprint (str:cstring): void {.importc: "print", noDecl.}
proc print* (a: varargs[string, `$`]) = consoleprint "$1: $2" % [consolePrefix, join (a, " ")]
type CallbackProc {.importc.} = proc () : cstring
proc regCallback (fn:CallbackProc) {.importc.}
proc runCallbacks ():cstring {.importc.}
proc `*` (s:string, n:Natural) : string = s.repeat (n)
proc outer (i:Natural) : (string, int) =
let c = $char (random (93) + 33)
let n = random (40)
let s = c * n
proc inner () : cstring = ("[$1]" % $n) & s & " <--"
regCallback (inner)
return (s, n)
var expected = "\n"
for i in 1 .. 10:
let (s, n) = outer (i)
expected &= ("($1)[$2]" % [$i, $n]) & s & " <--"
expected &= "\n"
let results = runCallbacks ()
doAssert(expected == results)

View File

@@ -107,6 +107,15 @@ proc specDefaults*(result: var TSpec) =
result.tline = 0
result.tcolumn = 0
proc parseTargets*(value: string): set[TTarget] =
for v in value.normalize.split:
case v
of "c": result.incl(targetC)
of "cpp", "c++": result.incl(targetCpp)
of "objc": result.incl(targetObjC)
of "js": result.incl(targetJS)
else: echo "target ignored: " & v
proc parseSpec*(filename: string): TSpec =
specDefaults(result)
result.file = filename

View File

@@ -33,6 +33,7 @@ Options:
--print also print results to the console
--failing only show failing/ignored tests
--pedantic return non-zero status code if there are failures
--targets:"c c++ js objc" run tests for specified targets (default: all)
""" % resultsFile
type
@@ -60,6 +61,8 @@ let
pegSuccess = peg"'Hint: operation successful'.*"
pegOfInterest = pegLineError / pegOtherError
var targets = {low(TTarget)..high(TTarget)}
proc callCompiler(cmdTemplate, filename, options: string,
target: TTarget): TSpec =
let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
@@ -275,6 +278,11 @@ proc analyzeAndConsolidateOutput(s: string): string =
proc testSpec(r: var TResults, test: TTest) =
# major entry point for a single test
if test.target notin targets:
r.addResult(test, "", "", reIgnored)
inc(r.skipped)
return
let tname = test.name.addFileExt(".nim")
inc(r.total)
var expected: TSpec
@@ -336,7 +344,7 @@ proc testSpec(r: var TResults, test: TTest) =
reExitCodesDiffer)
return
if bufB != expectedOut:
if bufB != expectedOut and expected.action != actionRunNoSpec:
if not (expected.substr and expectedOut in bufB):
given.err = reOutputsDiffer
r.addResult(test, expected.outp, bufB, reOutputsDiffer)
@@ -394,6 +402,7 @@ proc main() =
var optPrintResults = false
var optFailing = false
var optPedantic = false
var p = initOptParser()
p.next()
while p.kind == cmdLongoption:
@@ -401,6 +410,7 @@ proc main() =
of "print", "verbose": optPrintResults = true
of "failing": optFailing = true
of "pedantic": optPedantic = true
of "targets": targets = parseTargets(p.val.string)
else: quit Usage
p.next()
if p.kind != cmdArgument: quit Usage

View File

@@ -1,6 +1,7 @@
discard """
output: '''48
hel'''
hel
lo'''
"""
template optZero{x+x}(x: int): int = x*3
@@ -15,3 +16,8 @@ s[0] = "hello"
s[0] = substr(s[0], 0, 2)
echo s[0]
# Test varargs matching
proc someVarargProc(k: varargs[string]) = doAssert(false) # this should not get called
template someVarargProcSingleArg{someVarargProc([a])}(a: string) = echo a
someVarargProc("lo")

View File

@@ -6,13 +6,23 @@
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>$c.projectTitle</title>
<link rel="stylesheet" type="text/css" href="assets/style.css" />
<link rel="stylesheet" type="text/css" href="assets/style.css?t=2221" />
<link rel="shortcut icon" href="assets/images/favicon.ico">
#if len(rss) > 0:
<link href="$rss" title="Recent changes" type="application/atom+xml" rel="alternate">
#end if
</head>
<body>
<div id="bountysource">
<a href="https://salt.bountysource.com/teams/nim">
<div class="page-layout" style="padding: 2pt 2pt 2pt 30pt">
<img src="assets/bountysource/bountysource.png" style="width: 20px; float: left;">
<span style="margin-left: 10pt; float: left; margin-top: 2pt;">Fund Nim and help us develop it further!</span>
<img src="https://api.bountysource.com/badge/team?team_id=19072&style=raised" style="margin-top: 2pt; margin-left: 10pt"/>
</div>
</a>
</div>
<header id="head">
<div class="page-layout tall">
<div id="head-logo"></div>

View File

@@ -563,3 +563,14 @@ pre .end { background:url("images/tabEnd.png") no-repeat left bottom; }
border-collapse: collapse;
text-align: left;
border-spacing: 0px; }
#bountysource {
width: 100%;
height: 30px;
background-color: #19975d;
}
#bountysource a, #bountysource a:visited, #bountysource a:hover {
color: #1a1a1a;
}

View File

@@ -23,6 +23,15 @@ Changes affecting backwards compatibility
- Procedures in ``mersenne.nim`` (Mersenne Twister implementation) no longer
accept and produce ``int`` values which have platform-dependent size -
they use ``uint32`` instead.
- The ``strutils.unindent`` procedure has been rewritten. Its parameters now
match the parameters of ``strutils.indent``. See issue [#4037](https://github.com/nim-lang/Nim/issues/4037)
for more details.
- The ``matchers`` module has been deprecated. See issue [#2446](https://github.com/nim-lang/Nim/issues/2446)
for more details.
- The ``json.[]`` no longer returns ``nil`` when a key is not found. Instead it
raises a ``KeyError`` exception. You can compile with the ``-d:nimJsonGet``
flag to get a list of usages of ``[]``, as well as to restore the operator's
previous behaviour.
Library Additions