big rename

This commit is contained in:
Araq 2014-08-27 23:42:51 +02:00
commit 11b6958755
98 changed files with 2491 additions and 2341 deletions

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -21,6 +21,11 @@
## for i in 0 .. < 300:
## a.spawn(i, proc (x: int) {.thread.} = echo x)
## a.join()
##
## **Note**: This whole module is deprecated. Use `threadpool` and ``spawn``
## instead.
{.deprecated.}
from os import sleep

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -10,9 +10,12 @@
## This module implements some common generic algorithms.
type
TSortOrder* = enum ## sort order
SortOrder* = enum ## sort order
Descending, Ascending
{.deprecated: [TSortOrder: SortOrder].}
proc `*`*(x: int, order: TSortOrder): int {.inline.} =
## flips `x` if ``order == Descending``;
## if ``order == Ascending`` then `x` is returned.

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -13,7 +13,7 @@ import os, oids, tables, strutils, macros, times
import rawsockets, net
export TPort, TSocketFlags
export Port, SocketFlags
#{.injectStmt: newGcInvariant().}
@ -36,21 +36,24 @@ export TPort, TSocketFlags
# -- Futures
type
PFutureBase* = ref object of PObject
FutureBase* = ref object of RootObj
cb: proc () {.closure,gcsafe.}
finished: bool
error*: ref EBase
error*: ref Exception
errorStackTrace*: string
when not defined(release):
stackTrace: string ## For debugging purposes only.
id: int
fromProc: string
PFuture*[T] = ref object of PFutureBase
Future*[T] = ref object of FutureBase
value: T
{.deprecated: [PFutureBase: FutureBase, PFuture: Future].}
var currentID* = 0
proc newFuture*[T](fromProc: string = "unspecified"): PFuture[T] =
proc newFuture*[T](fromProc: string = "unspecified"): Future[T] =
## Creates a new future.
##
## Specifying ``fromProc``, which is a string specifying the name of the proc
@ -63,7 +66,7 @@ proc newFuture*[T](fromProc: string = "unspecified"): PFuture[T] =
result.fromProc = fromProc
currentID.inc()
proc checkFinished[T](future: PFuture[T]) =
proc checkFinished[T](future: Future[T]) =
when not defined(release):
if future.finished:
echo("<-----> ", future.id, " ", future.fromProc)
@ -76,7 +79,7 @@ proc checkFinished[T](future: PFuture[T]) =
echo getStackTrace()
assert false
proc complete*[T](future: PFuture[T], val: T) =
proc complete*[T](future: Future[T], val: T) =
## Completes ``future`` with value ``val``.
#assert(not future.finished, "Future already finished, cannot finish twice.")
checkFinished(future)
@ -86,7 +89,7 @@ proc complete*[T](future: PFuture[T], val: T) =
if future.cb != nil:
future.cb()
proc complete*(future: PFuture[void]) =
proc complete*(future: Future[void]) =
## Completes a void ``future``.
#assert(not future.finished, "Future already finished, cannot finish twice.")
checkFinished(future)
@ -95,7 +98,7 @@ proc complete*(future: PFuture[void]) =
if future.cb != nil:
future.cb()
proc fail*[T](future: PFuture[T], error: ref EBase) =
proc fail*[T](future: Future[T], error: ref Exception) =
## Completes ``future`` with ``error``.
#assert(not future.finished, "Future already finished, cannot finish twice.")
checkFinished(future)
@ -111,8 +114,9 @@ proc fail*[T](future: PFuture[T], error: ref EBase) =
# TODO: This may turn out to be a bad idea.
# Turns out this is a bad idea.
#raise error
discard
proc `callback=`*(future: PFutureBase, cb: proc () {.closure,gcsafe.}) =
proc `callback=`*(future: FutureBase, cb: proc () {.closure,gcsafe.}) =
## Sets the callback proc to be called when the future completes.
##
## If future has already completed then ``cb`` will be called immediately.
@ -123,23 +127,23 @@ proc `callback=`*(future: PFutureBase, cb: proc () {.closure,gcsafe.}) =
if future.finished:
future.cb()
proc `callback=`*[T](future: PFuture[T],
cb: proc (future: PFuture[T]) {.closure,gcsafe.}) =
proc `callback=`*[T](future: Future[T],
cb: proc (future: Future[T]) {.closure,gcsafe.}) =
## Sets the callback proc to be called when the future completes.
##
## If future has already completed then ``cb`` will be called immediately.
future.callback = proc () = cb(future)
proc echoOriginalStackTrace[T](future: PFuture[T]) =
proc echoOriginalStackTrace[T](future: Future[T]) =
# TODO: Come up with something better.
when not defined(release):
echo("Original stack trace in ", future.fromProc, ":")
if not future.errorStackTrace.isNil() and future.errorStackTrace != "":
if not future.errorStackTrace.isNil and future.errorStackTrace != "":
echo(future.errorStackTrace)
else:
echo("Empty or nil stack trace.")
proc read*[T](future: PFuture[T]): T =
proc read*[T](future: Future[T]): T =
## Retrieves the value of ``future``. Future must be finished otherwise
## this function will fail with a ``EInvalidValue`` exception.
##
@ -154,22 +158,22 @@ proc read*[T](future: PFuture[T]): T =
# TODO: Make a custom exception type for this?
raise newException(EInvalidValue, "Future still in progress.")
proc readError*[T](future: PFuture[T]): ref EBase =
proc readError*[T](future: Future[T]): ref EBase =
if future.error != nil: return future.error
else:
raise newException(EInvalidValue, "No error in future.")
proc finished*[T](future: PFuture[T]): bool =
proc finished*[T](future: Future[T]): bool =
## Determines whether ``future`` has completed.
##
## ``True`` may indicate an error or a value. Use ``failed`` to distinguish.
future.finished
proc failed*(future: PFutureBase): bool =
proc failed*(future: FutureBase): bool =
## Determines whether ``future`` completed with an error.
future.error != nil
proc asyncCheck*[T](future: PFuture[T]) =
proc asyncCheck*[T](future: Future[T]) =
## Sets a callback on ``future`` which raises an exception if the future
## finished with an error.
##
@ -180,7 +184,7 @@ proc asyncCheck*[T](future: PFuture[T]) =
echoOriginalStackTrace(future)
raise future.error
proc `and`*[T, Y](fut1: PFuture[T], fut2: PFuture[Y]): PFuture[void] =
proc `and`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
## Returns a future which will complete once both ``fut1`` and ``fut2``
## complete.
var retFuture = newFuture[void]()
@ -192,7 +196,7 @@ proc `and`*[T, Y](fut1: PFuture[T], fut2: PFuture[Y]): PFuture[void] =
if fut1.finished: retFuture.complete()
return retFuture
proc `or`*[T, Y](fut1: PFuture[T], fut2: PFuture[Y]): PFuture[void] =
proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
## Returns a future which will complete once either ``fut1`` or ``fut2``
## complete.
var retFuture = newFuture[void]()
@ -203,7 +207,7 @@ proc `or`*[T, Y](fut1: PFuture[T], fut2: PFuture[Y]): PFuture[void] =
type
PDispatcherBase = ref object of PObject
timers: seq[tuple[finishAt: float, fut: PFuture[void]]]
timers: seq[tuple[finishAt: float, fut: Future[void]]]
proc processTimers(p: PDispatcherBase) =
var oldTimers = p.timers
@ -375,10 +379,10 @@ when defined(windows) or defined(nimdoc):
RemoteSockaddr, RemoteSockaddrLength)
proc connect*(socket: TAsyncFD, address: string, port: TPort,
af = AF_INET): PFuture[void] =
af = AF_INET): Future[void] =
## Connects ``socket`` to server at ``address:port``.
##
## Returns a ``PFuture`` which will complete when the connection succeeds
## Returns a ``Future`` which will complete when the connection succeeds
## or an error occurs.
verifyPresence(socket)
var retFuture = newFuture[void]("connect")
@ -437,7 +441,7 @@ when defined(windows) or defined(nimdoc):
return retFuture
proc recv*(socket: TAsyncFD, size: int,
flags = {TSocketFlags.SafeDisconn}): PFuture[string] =
flags = {TSocketFlags.SafeDisconn}): Future[string] =
## Reads **up to** ``size`` bytes from ``socket``. Returned future will
## complete once all the data requested is read, a part of the data has been
## read, or the socket has disconnected in which case the future will
@ -525,7 +529,7 @@ when defined(windows) or defined(nimdoc):
return retFuture
proc send*(socket: TAsyncFD, data: string,
flags = {TSocketFlags.SafeDisconn}): PFuture[void] =
flags = {TSocketFlags.SafeDisconn}): Future[void] =
## Sends ``data`` to ``socket``. The returned future will complete once all
## data has been sent.
verifyPresence(socket)
@ -568,7 +572,7 @@ when defined(windows) or defined(nimdoc):
return retFuture
proc acceptAddr*(socket: TAsyncFD, flags = {TSocketFlags.SafeDisconn}):
PFuture[tuple[address: string, client: TAsyncFD]] =
Future[tuple[address: string, client: TAsyncFD]] =
## Accepts a new connection. Returns a future containing the client socket
## corresponding to that connection and the remote address of the client.
## The future will complete when the connection is successfully accepted.
@ -789,7 +793,7 @@ else:
processTimers(p)
proc connect*(socket: TAsyncFD, address: string, port: TPort,
af = AF_INET): PFuture[void] =
af = AF_INET): Future[void] =
var retFuture = newFuture[void]("connect")
proc cb(sock: TAsyncFD): bool =
@ -824,7 +828,7 @@ else:
return retFuture
proc recv*(socket: TAsyncFD, size: int,
flags = {TSocketFlags.SafeDisconn}): PFuture[string] =
flags = {TSocketFlags.SafeDisconn}): Future[string] =
var retFuture = newFuture[string]("recv")
var readBuffer = newString(size)
@ -855,7 +859,7 @@ else:
return retFuture
proc send*(socket: TAsyncFD, data: string,
flags = {TSocketFlags.SafeDisconn}): PFuture[void] =
flags = {TSocketFlags.SafeDisconn}): Future[void] =
var retFuture = newFuture[void]("send")
var written = 0
@ -887,7 +891,7 @@ else:
return retFuture
proc acceptAddr*(socket: TAsyncFD, flags = {TSocketFlags.SafeDisconn}):
PFuture[tuple[address: string, client: TAsyncFD]] =
Future[tuple[address: string, client: TAsyncFD]] =
var retFuture = newFuture[tuple[address: string,
client: TAsyncFD]]("acceptAddr")
proc cb(sock: TAsyncFD): bool =
@ -912,7 +916,7 @@ else:
addRead(socket, cb)
return retFuture
proc sleepAsync*(ms: int): PFuture[void] =
proc sleepAsync*(ms: int): Future[void] =
## Suspends the execution of the current async procedure for the next
## ``ms`` miliseconds.
var retFuture = newFuture[void]("sleepAsync")
@ -921,14 +925,14 @@ proc sleepAsync*(ms: int): PFuture[void] =
return retFuture
proc accept*(socket: TAsyncFD,
flags = {TSocketFlags.SafeDisconn}): PFuture[TAsyncFD] =
flags = {TSocketFlags.SafeDisconn}): Future[TAsyncFD] =
## Accepts a new connection. Returns a future containing the client socket
## corresponding to that connection.
## The future will complete when the connection is successfully accepted.
var retFut = newFuture[TAsyncFD]("accept")
var fut = acceptAddr(socket, flags)
fut.callback =
proc (future: PFuture[tuple[address: string, client: TAsyncFD]]) =
proc (future: Future[tuple[address: string, client: TAsyncFD]]) =
assert future.finished
if future.failed:
retFut.fail(future.error)
@ -1111,12 +1115,12 @@ macro async*(prc: stmt): stmt {.immediate.} =
hint("Processing " & prc[0].getName & " as an async proc.")
let returnType = prc[3][0]
# Verify that the return type is a PFuture[T]
# Verify that the return type is a Future[T]
if returnType.kind == nnkIdent:
error("Expected return type of 'PFuture' got '" & $returnType & "'")
error("Expected return type of 'Future' got '" & $returnType & "'")
elif returnType.kind == nnkBracketExpr:
if $returnType[0] != "PFuture":
error("Expected return type of 'PFuture' got '" & $returnType[0] & "'")
if $returnType[0] != "Future":
error("Expected return type of 'Future' got '" & $returnType[0] & "'")
let subtypeIsVoid = returnType.kind == nnkEmpty or
(returnType.kind == nnkBracketExpr and
@ -1137,7 +1141,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
subRetType),
newLit(prc[0].getName)))) # Get type from return type of this proc
# -> iterator nameIter(): PFutureBase {.closure.} =
# -> iterator nameIter(): FutureBase {.closure.} =
# -> var result: T
# -> <proc_body>
# -> complete(retFuture, result)
@ -1153,7 +1157,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
# -> complete(retFuture)
procBody.add(newCall(newIdentNode("complete"), retFutureSym))
var closureIterator = newProc(iteratorNameSym, [newIdentNode("PFutureBase")],
var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
procBody, nnkIteratorDef)
closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
outerProcBody.add(closureIterator)
@ -1176,8 +1180,8 @@ macro async*(prc: stmt): stmt {.immediate.} =
if subtypeIsVoid:
# Add discardable pragma.
if returnType.kind == nnkEmpty:
# Add PFuture[void]
result[3][0] = parseExpr("PFuture[void]")
# Add Future[void]
result[3][0] = parseExpr("Future[void]")
result[6] = outerProcBody
@ -1185,7 +1189,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
#if prc[0].getName == "processClient":
# echo(toStrLit(result))
proc recvLine*(socket: TAsyncFD): PFuture[string] {.async.} =
proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
## Reads a line of data from ``socket``. Returned future will complete once
## a full line is read or an error occurs.
##

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -13,7 +13,7 @@
import strtabs, asyncnet, asyncdispatch, parseutils, uri, strutils
type
TRequest* = object
Request* = object
client*: PAsyncSocket # TODO: Separate this into a Response object?
reqMethod*: string
headers*: PStringTable
@ -22,10 +22,10 @@ type
hostname*: string ## The hostname of the client that made the request.
body*: string
PAsyncHttpServer* = ref object
AsyncHttpServer* = ref object
socket: PAsyncSocket
THttpCode* = enum
HttpCode* = enum
Http200 = "200 OK",
Http303 = "303 Moved",
Http400 = "400 Bad Request",
@ -33,10 +33,13 @@ type
Http500 = "500 Internal Server Error",
Http502 = "502 Bad Gateway"
THttpVersion* = enum
HttpVersion* = enum
HttpVer11,
HttpVer10
{.deprecated: [TRequest: Request, PAsyncHttpServer: AsyncHttpServer,
THttpCode: HttpCode, THttpVersion: HttpVersion].}
proc `==`*(protocol: tuple[orig: string, major, minor: int],
ver: THttpVersion): bool =
let major =

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf, Dominik Picheta
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -10,8 +10,8 @@ include "system/inclrtl"
import sockets, os
## This module implements an asynchronous event loop together with asynchronous sockets
## which use this event loop.
## This module implements an asynchronous event loop together with asynchronous
## sockets which use this event loop.
## It is akin to Python's asyncore module. Many modules that use sockets
## have an implementation for this module, those modules should all have a
## ``register`` function which you should use to add the desired objects to a
@ -31,10 +31,10 @@ import sockets, os
##
## Most (if not all) modules that use asyncio provide a userArg which is passed
## on with the events. The type that you set userArg to must be inheriting from
## TObject!
## ``RootObj``!
##
## **Note:** If you want to provide async ability to your module please do not
## use the ``TDelegate`` object, instead use ``PAsyncSocket``. It is possible
## use the ``Delegate`` object, instead use ``AsyncSocket``. It is possible
## that in the future this type's fields will not be exported therefore breaking
## your code.
##
@ -44,10 +44,10 @@ import sockets, os
## Asynchronous sockets
## ====================
##
## For most purposes you do not need to worry about the ``TDelegate`` type. The
## ``PAsyncSocket`` is what you are after. It's a reference to the ``TAsyncSocket``
## object. This object defines events which you should overwrite by your own
## procedures.
## For most purposes you do not need to worry about the ``Delegate`` type. The
## ``AsyncSocket`` is what you are after. It's a reference to
## the ``AsyncSocketObj`` object. This object defines events which you should
## overwrite by your own procedures.
##
## For server sockets the only event you need to worry about is the ``handleAccept``
## event, in your handleAccept proc you should call ``accept`` on the server
@ -57,13 +57,13 @@ import sockets, os
##
## An example ``handleAccept`` follows:
##
## .. code-block:: nimrod
## .. code-block:: nim
##
## var disp: PDispatcher = newDispatcher()
## var disp = newDispatcher()
## ...
## proc handleAccept(s: PAsyncSocket) =
## proc handleAccept(s: AsyncSocket) =
## echo("Accepted client.")
## var client: PAsyncSocket
## var client: AsyncSocket
## new(client)
## s.accept(client)
## client.handleRead = ...
@ -76,29 +76,29 @@ import sockets, os
## the socket has established a connection to a server socket; from that point
## it can be safely written to.
##
## Getting a blocking client from a PAsyncSocket
## Getting a blocking client from an AsyncSocket
## =============================================
##
## If you need a asynchronous server socket but you wish to process the clients
## synchronously then you can use the ``getSocket`` converter to get a TSocket
## object from the PAsyncSocket object, this can then be combined with ``accept``
## like so:
## synchronously then you can use the ``getSocket`` converter to get
## a ``Socket`` from the ``AsyncSocket`` object, this can then be combined
## with ``accept`` like so:
##
## .. code-block:: nimrod
## .. code-block:: nim
##
## proc handleAccept(s: PAsyncSocket) =
## var client: TSocket
## proc handleAccept(s: AsyncSocket) =
## var client: Socket
## getSocket(s).accept(client)
when defined(windows):
from winlean import TTimeVal, TSocketHandle, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
from winlean import TimeVal, SocketHandle, FdSet, FD_ZERO, FD_SET, FD_ISSET, select
else:
from posix import TTimeVal, TSocketHandle, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
from posix import TimeVal, SocketHandle, FdSet, FD_ZERO, FD_SET, FD_ISSET, select
type
TDelegate* = object
fd*: TSocketHandle
deleVal*: PObject
DelegateObj* = object
fd*: SocketHandle
deleVal*: RootRef
handleRead*: proc (h: PObject) {.nimcall, gcsafe.}
handleWrite*: proc (h: PObject) {.nimcall, gcsafe.}
@ -107,18 +107,18 @@ type
open*: bool
task*: proc (h: PObject) {.nimcall, gcsafe.}
mode*: TFileMode
mode*: FileMode
PDelegate* = ref TDelegate
Delegate* = ref DelegateObj
PDispatcher* = ref TDispatcher
TDispatcher = object
Dispatcher* = ref DispatcherObj
DispatcherObj = object
delegates: seq[PDelegate]
PAsyncSocket* = ref TAsyncSocket
TAsyncSocket* = object of TObject
socket: TSocket
info: TInfo
AsyncSocket* = ref AsyncSocketObj
AsyncSocketObj* = object of RootObj
socket: Socket
info: SocketStatus
handleRead*: proc (s: PAsyncSocket) {.closure, gcsafe.}
handleWrite: proc (s: PAsyncSocket) {.closure, gcsafe.}
@ -134,10 +134,17 @@ type
proto: TProtocol
deleg: PDelegate
TInfo* = enum
SocketStatus* = enum
SockIdle, SockConnecting, SockConnected, SockListening, SockClosed,
SockUDPBound
{.deprecated: [TDelegate: DelegateObj, PDelegate: Delegate,
TProcessOption: ProcessOption,
TInfo: SocketStatus, PAsyncSocket: AsyncSocket, TAsyncSocket: AsyncSocketObj,
TDispatcher: DispatcherObj, PDispatcher: Dispatcher,
].}
proc newDelegate*(): PDelegate =
## Creates a new delegate.
new(result)

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -19,9 +19,9 @@
##
## import asyncnet, asyncdispatch
##
## var clients: seq[PAsyncSocket] = @[]
## var clients: seq[AsyncSocket] = @[]
##
## proc processClient(client: PAsyncSocket) {.async.} =
## proc processClient(client: AsyncSocket) {.async.} =
## while true:
## let line = await client.recvLine()
## for c in clients:
@ -29,7 +29,7 @@
##
## proc serve() {.async.} =
## var server = newAsyncSocket()
## server.bindAddr(TPort(12345))
## server.bindAddr(Port(12345))
## server.listen()
##
## while true:
@ -54,8 +54,10 @@ when defined(ssl):
type
# TODO: I would prefer to just do:
# PAsyncSocket* {.borrow: `.`.} = distinct PSocket. But that doesn't work.
TAsyncSocket {.borrow: `.`.} = distinct TSocketImpl
PAsyncSocket* = ref TAsyncSocket
AsyncSocketDesc {.borrow: `.`.} = distinct TSocketImpl
AsyncSocket* = ref AsyncSocketDesc
{.deprecated: [PAsyncSocket: AsyncSocket].}
# TODO: Save AF, domain etc info and reuse it in procs which need it like connect.

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2013 Robert Persson
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2013 Robert Persson
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -44,5 +44,5 @@ proc openDefaultBrowser*(url: string) =
# we use ``startProcess`` here because we don't want to block!
discard startProcess(command=b, args=[url], options={poUseShell})
return
except EOS:
except OSError:
discard

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -9,7 +9,7 @@
## This module implements helper procs for CGI applications. Example:
##
## .. code-block:: Nimrod
## .. code-block:: Nim
##
## import strtabs, cgi
##
@ -93,12 +93,14 @@ proc XMLencode*(s: string): string =
for i in 0..len(s)-1: addXmlChar(result, s[i])
type
ECgi* = object of IOError ## the exception that is raised, if a CGI error occurs
TRequestMethod* = enum ## the used request method
CgiError* = object of IOError ## exception that is raised if a CGI error occurs
RequestMethod* = enum ## the used request method
methodNone, ## no REQUEST_METHOD environment variable
methodPost, ## query uses the POST method
methodGet ## query uses the GET method
{.deprecated: [TRequestMethod: RequestMethod, ECgi: CgiError].}
proc cgiError*(msg: string) {.noreturn.} =
## raises an ECgi exception with message `msg`.
var e: ref ECgi
@ -377,7 +379,7 @@ proc setCookie*(name, value: string) =
write(stdout, "Set-Cookie: ", name, "=", value, "\n")
var
gcookies {.threadvar.}: PStringTable
gcookies {.threadvar.}: StringTableRef
proc getCookie*(name: string): TaintedString =
## Gets a cookie. If no cookie of `name` exists, "" is returned.

View file

@ -1,8 +1,40 @@
#nimrod c -t:-march=i686 --cpu:amd64 --threads:on -d:release lockfreehash.nim
import baseutils, unsigned, math, hashes
import unsigned, math, hashes
#------------------------------------------------------------------------------
## Memory Utility Functions
proc newHeap*[T](): ptr T =
result = cast[ptr T](alloc0(sizeof(T)))
proc copyNew*[T](x: var T): ptr T =
var
size = sizeof(T)
mem = alloc(size)
copyMem(mem, x.addr, size)
return cast[ptr T](mem)
proc copyTo*[T](val: var T, dest: int) =
copyMem(pointer(dest), val.addr, sizeof(T))
proc allocType*[T](): pointer = alloc(sizeof(T))
proc newShared*[T](): ptr T =
result = cast[ptr T](allocShared0(sizeof(T)))
proc copyShared*[T](x: var T): ptr T =
var
size = sizeof(T)
mem = allocShared(size)
copyMem(mem, x.addr, size)
return cast[ptr T](mem)
#------------------------------------------------------------------------------
## Pointer arithmetic
proc `+`*(p: pointer, i: int): pointer {.inline.} =
cast[pointer](cast[int](p) + i)
const
minTableSize = 8
@ -194,7 +226,7 @@ proc copySlot[K,V](idx: int, oldTbl: var PConcTable[K,V], newTbl: var PConcTable
#Prevent new values from appearing in the old table by priming
oldVal = atomic_load_n(oldTbl[idx].value.addr, ATOMIC_RELAXED)
while not isPrime(oldVal):
var box = if oldVal == NULL or isTomb(oldVal) : oldVal.setTomb.setPrime
var box = if oldVal == 0 or isTomb(oldVal) : oldVal.setTomb.setPrime
else: oldVal.setPrime
if atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr,
box, false, ATOMIC_RELAXED, ATOMIC_RELAXED):
@ -209,8 +241,8 @@ proc copySlot[K,V](idx: int, oldTbl: var PConcTable[K,V], newTbl: var PConcTable
return false
if isTomb(oldVal):
echo("oldVal is Tomb!!!, should not happen")
if pop(oldVal) != NULL:
result = setVal(newTbl, pop(oldKey), pop(oldVal), NULL, true) == NULL
if pop(oldVal) != 0:
result = setVal(newTbl, pop(oldKey), pop(oldVal), 0, true) == 0
if result:
#echo("Copied a Slot! idx= " & $idx & " key= " & $oldKey & " val= " & $oldVal)
else:
@ -323,7 +355,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
idx = idx and (table.len - 1)
#echo("try set idx = " & $idx & "for" & $key)
var
probedKey = NULL
probedKey = 0
openKey = atomic_compare_exchange_n(table[idx].key.addr, probedKey.addr,
key, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
if openKey:
@ -339,7 +371,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
if keyEQ[K](probedKey, key):
#echo("we found the matching slot")
break # We found a matching slot
if (not(expVal != NULL and match)) and (probes >= reProbeLimit or key.isTomb):
if (not(expVal != 0 and match)) and (probes >= reProbeLimit or key.isTomb):
if key.isTomb: echo("Key is Tombstone")
#if probes >= reProbeLimit: echo("Too much probing " & $probes)
#echo("try to resize")
@ -361,7 +393,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
return oldVal
nextTable = atomic_load_n(table.next.addr, ATOMIC_SEQ_CST)
if nextTable == nil and
((oldVal == NULL and
((oldVal == 0 and
(probes >= reProbeLimit or table.used / table.len > 0.8)) or
(isPrime(oldVal))):
if table.used / table.len > 0.8: echo("resize because usage ratio = " &
@ -380,12 +412,12 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
if atomic_compare_exchange_n(table[idx].value.addr, oldVal.addr,
val, false, ATOMIC_RELEASE, ATOMIC_RELAXED):
#echo("val set at table " & $cast[int](table))
if expVal != NULL:
if (oldVal == NULL or isTomb(oldVal)) and not isTomb(val):
if expVal != 0:
if (oldVal == 0 or isTomb(oldVal)) and not isTomb(val):
discard atomic_add_fetch(table.active.addr, 1, ATOMIC_RELAXED)
elif not (oldVal == NULL or isTomb(oldVal)) and isTomb(val):
elif not (oldVal == 0 or isTomb(oldVal)) and isTomb(val):
discard atomic_add_fetch(table.active.addr, -1, ATOMIC_RELAXED)
if oldVal == NULL and expVal != NULL:
if oldVal == 0 and expVal != 0:
return setTomb(oldVal)
else: return oldVal
if isPrime(oldVal):
@ -415,7 +447,7 @@ proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
if not isPrime(val):
if isTomb(val):
#echo("val was tomb but not prime")
return NULL
return 0
else:
#echo("-GotIt- idx = ", idx, " key = ", key, " val ", val )
return val
@ -427,7 +459,7 @@ proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
if probes >= reProbeLimit*4 or key.isTomb:
if newTable == nil:
#echo("too many probes and no new table ", key, " ", idx )
return NULL
return 0
else:
newTable = helpCopy(table)
return getVal(newTable, key)
@ -437,10 +469,10 @@ proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
#------------------------------------------------------------------------------
#proc set*(table: var PConcTable[TRaw,TRaw], key: TRaw, val: TRaw) =
# discard setVal(table, pack(key), pack(key), NULL, false)
# discard setVal(table, pack(key), pack(key), 0, false)
#proc set*[V](table: var PConcTable[TRaw,V], key: TRaw, val: ptr V) =
# discard setVal(table, pack(key), cast[int](val), NULL, false)
# discard setVal(table, pack(key), cast[int](val), 0, false)
proc set*[K,V](table: var PConcTable[K,V], key: var K, val: var V) =
when not (K is TRaw):
@ -451,10 +483,10 @@ proc set*[K,V](table: var PConcTable[K,V], key: var K, val: var V) =
var newVal = cast[int](copyShared(val))
else:
var newVal = pack(val)
var oldPtr = pop(setVal(table, newKey, newVal, NULL, false))
var oldPtr = pop(setVal(table, newKey, newVal, 0, false))
#echo("oldPtr = ", cast[int](oldPtr), " newPtr = ", cast[int](newPtr))
when not (V is TRaw):
if newVal != oldPtr and oldPtr != NULL:
if newVal != oldPtr and oldPtr != 0:
deallocShared(cast[ptr V](oldPtr))
@ -573,10 +605,3 @@ when isMainModule:
# echo(i, " = ", hashInt(i) and 8191)
deleteConcTable(table)

View file

@ -1,41 +0,0 @@
#------------------------------------------------------------------------------
## Useful Constants
const NULL* = 0
#------------------------------------------------------------------------------
## Memory Utility Functions
proc newHeap*[T](): ptr T =
result = cast[ptr T](alloc0(sizeof(T)))
proc copyNew*[T](x: var T): ptr T =
var
size = sizeof(T)
mem = alloc(size)
copyMem(mem, x.addr, size)
return cast[ptr T](mem)
proc copyTo*[T](val: var T, dest: int) =
copyMem(pointer(dest), val.addr, sizeof(T))
proc allocType*[T](): pointer = alloc(sizeof(T))
proc newShared*[T](): ptr T =
result = cast[ptr T](allocShared0(sizeof(T)))
proc copyShared*[T](x: var T): ptr T =
var
size = sizeof(T)
mem = allocShared(size)
copyMem(mem, x.addr, size)
return cast[ptr T](mem)
#------------------------------------------------------------------------------
## Pointer arithmetic
proc `+`*(p: pointer, i: int): pointer {.inline.} =
cast[pointer](cast[int](p) + i)

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -12,30 +12,32 @@
## by Adam Langley.
type
TNode[T] = object {.pure, final, acyclic.}
NodeObj[T] = object {.pure, final, acyclic.}
byte: int ## byte index of the difference
otherbits: char
case isLeaf: bool
of false: child: array[0..1, ref TNode[T]]
of false: child: array[0..1, ref NodeObj[T]]
of true:
key: string
when T isnot void:
val: T
PNode[T] = ref TNode[T]
TCritBitTree*[T] = object {.
Node[T] = ref NodeObj[T]
CritBitTree*[T] = object {.
pure, final.} ## The crit bit tree can either be used
## as a mapping from strings to
## some type ``T`` or as a set of
## strings if ``T`` is void.
root: PNode[T]
root: Node[T]
count: int
proc len*[T](c: TCritBitTree[T]): int =
{.deprecated: [TCritBitTree: CritBitTree].}
proc len*[T](c: CritBitTree[T]): int =
## returns the number of elements in `c` in O(1).
result = c.count
proc rawGet[T](c: TCritBitTree[T], key: string): PNode[T] =
proc rawGet[T](c: CritBitTree[T], key: string): Node[T] =
var it = c.root
while it != nil:
if not it.isLeaf:
@ -45,15 +47,15 @@ proc rawGet[T](c: TCritBitTree[T], key: string): PNode[T] =
else:
return if it.key == key: it else: nil
proc contains*[T](c: TCritBitTree[T], key: string): bool {.inline.} =
proc contains*[T](c: CritBitTree[T], key: string): bool {.inline.} =
## returns true iff `c` contains the given `key`.
result = rawGet(c, key) != nil
proc hasKey*[T](c: TCritBitTree[T], key: string): bool {.inline.} =
proc hasKey*[T](c: CritBitTree[T], key: string): bool {.inline.} =
## alias for `contains`.
result = rawGet(c, key) != nil
proc rawInsert[T](c: var TCritBitTree[T], key: string): PNode[T] =
proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] =
if c.root == nil:
new c.root
c.root.isleaf = true
@ -84,7 +86,7 @@ proc rawInsert[T](c: var TCritBitTree[T], key: string): PNode[T] =
let ch = it.key[newByte]
let dir = (1 + (ord(ch) or newOtherBits)) shr 8
var inner: PNode[T]
var inner: Node[T]
new inner
new result
result.isLeaf = true
@ -106,7 +108,7 @@ proc rawInsert[T](c: var TCritBitTree[T], key: string): PNode[T] =
wherep[] = inner
inc c.count
proc containsOrIncl*[T](c: var TCritBitTree[T], key: string, val: T): bool =
proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: T): bool =
## returns true iff `c` contains the given `key`. If the key does not exist
## ``c[key] = val`` is performed.
let oldCount = c.count
@ -115,23 +117,23 @@ proc containsOrIncl*[T](c: var TCritBitTree[T], key: string, val: T): bool =
when T isnot void:
if not result: n.val = val
proc containsOrIncl*(c: var TCritBitTree[void], key: string): bool =
proc containsOrIncl*(c: var CritBitTree[void], key: string): bool =
## returns true iff `c` contains the given `key`. If the key does not exist
## it is inserted into `c`.
let oldCount = c.count
var n = rawInsert(c, key)
result = c.count == oldCount
proc incl*(c: var TCritBitTree[void], key: string) =
proc incl*(c: var CritBitTree[void], key: string) =
## includes `key` in `c`.
discard rawInsert(c, key)
proc `[]=`*[T](c: var TCritBitTree[T], key: string, val: T) =
proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) =
## puts a (key, value)-pair into `t`.
var n = rawInsert(c, key)
n.val = val
proc `[]`*[T](c: TCritBitTree[T], key: string): T {.inline.} =
proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} =
## retrieves the value at ``c[key]``. If `key` is not in `t`,
## default empty value for the type `B` is returned
## and no exception is raised. One can check with ``hasKey`` whether the key
@ -139,22 +141,22 @@ proc `[]`*[T](c: TCritBitTree[T], key: string): T {.inline.} =
let n = rawGet(c, key)
if n != nil: result = n.val
proc mget*[T](c: var TCritBitTree[T], key: string): var T {.inline.} =
proc mget*[T](c: var CritBitTree[T], key: string): var T {.inline.} =
## retrieves the value at ``c[key]``. The value can be modified.
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
## If `key` is not in `t`, the ``KeyError`` exception is raised.
let n = rawGet(c, key)
if n != nil: result = n.val
else: raise newException(EInvalidKey, "key not found: " & $key)
else: raise newException(KeyError, "key not found: " & $key)
proc excl*[T](c: var TCritBitTree[T], key: string) =
proc excl*[T](c: var CritBitTree[T], key: string) =
## removes `key` (and its associated value) from the set `c`.
## If the `key` does not exist, nothing happens.
var p = c.root
var wherep = addr(c.root)
var whereq: ptr PNode = nil
var whereq: ptr Node[T] = nil
if p == nil: return
var dir = 0
var q: PNode
var q: Node[T]
while not p.isLeaf:
whereq = wherep
q = p
@ -170,7 +172,7 @@ proc excl*[T](c: var TCritBitTree[T], key: string) =
whereq[] = q.child[1 - dir]
dec c.count
iterator leaves[T](n: PNode[T]): PNode[T] =
iterator leaves[T](n: Node[T]): Node[T] =
if n != nil:
# XXX actually we could compute the necessary stack size in advance:
# it's rougly log2(c.count).
@ -183,33 +185,33 @@ iterator leaves[T](n: PNode[T]): PNode[T] =
assert(it != nil)
yield it
iterator keys*[T](c: TCritBitTree[T]): string =
iterator keys*[T](c: CritBitTree[T]): string =
## yields all keys in lexicographical order.
for x in leaves(c.root): yield x.key
iterator values*[T](c: TCritBitTree[T]): T =
iterator values*[T](c: CritBitTree[T]): T =
## yields all values of `c` in the lexicographical order of the
## corresponding keys.
for x in leaves(c.root): yield x.val
iterator mvalues*[T](c: var TCritBitTree[T]): var T =
iterator mvalues*[T](c: var CritBitTree[T]): var T =
## yields all values of `c` in the lexicographical order of the
## corresponding keys. The values can be modified.
for x in leaves(c.root): yield x.val
iterator items*[T](c: TCritBitTree[T]): string =
iterator items*[T](c: CritBitTree[T]): string =
## yields all keys in lexicographical order.
for x in leaves(c.root): yield x.key
iterator pairs*[T](c: TCritBitTree[T]): tuple[key: string, val: T] =
iterator pairs*[T](c: CritBitTree[T]): tuple[key: string, val: T] =
## yields all (key, value)-pairs of `c`.
for x in leaves(c.root): yield (x.key, x.val)
iterator mpairs*[T](c: var TCritBitTree[T]): tuple[key: string, val: var T] =
iterator mpairs*[T](c: var CritBitTree[T]): tuple[key: string, val: var T] =
## yields all (key, value)-pairs of `c`. The yielded values can be modified.
for x in leaves(c.root): yield (x.key, x.val)
proc allprefixedAux[T](c: TCritBitTree[T], key: string): PNode[T] =
proc allprefixedAux[T](c: CritBitTree[T], key: string): Node[T] =
var p = c.root
var top = p
if p != nil:
@ -223,42 +225,42 @@ proc allprefixedAux[T](c: TCritBitTree[T], key: string): PNode[T] =
if p.key[i] != key[i]: return
result = top
iterator itemsWithPrefix*[T](c: TCritBitTree[T], prefix: string): string =
iterator itemsWithPrefix*[T](c: CritBitTree[T], prefix: string): string =
## yields all keys starting with `prefix`.
let top = allprefixedAux(c, prefix)
for x in leaves(top): yield x.key
iterator keysWithPrefix*[T](c: TCritBitTree[T], prefix: string): string =
iterator keysWithPrefix*[T](c: CritBitTree[T], prefix: string): string =
## yields all keys starting with `prefix`.
let top = allprefixedAux(c, prefix)
for x in leaves(top): yield x.key
iterator valuesWithPrefix*[T](c: TCritBitTree[T], prefix: string): T =
iterator valuesWithPrefix*[T](c: CritBitTree[T], prefix: string): T =
## yields all values of `c` starting with `prefix` of the
## corresponding keys.
let top = allprefixedAux(c, prefix)
for x in leaves(top): yield x.val
iterator mvaluesWithPrefix*[T](c: var TCritBitTree[T], prefix: string): var T =
iterator mvaluesWithPrefix*[T](c: var CritBitTree[T], prefix: string): var T =
## yields all values of `c` starting with `prefix` of the
## corresponding keys. The values can be modified.
let top = allprefixedAux(c, prefix)
for x in leaves(top): yield x.val
iterator pairsWithPrefix*[T](c: TCritBitTree[T],
iterator pairsWithPrefix*[T](c: CritBitTree[T],
prefix: string): tuple[key: string, val: T] =
## yields all (key, value)-pairs of `c` starting with `prefix`.
let top = allprefixedAux(c, prefix)
for x in leaves(top): yield (x.key, x.val)
iterator mpairsWithPrefix*[T](c: var TCritBitTree[T],
iterator mpairsWithPrefix*[T](c: var CritBitTree[T],
prefix: string): tuple[key: string, val: var T] =
## yields all (key, value)-pairs of `c` starting with `prefix`.
## The yielded values can be modified.
let top = allprefixedAux(c, prefix)
for x in leaves(top): yield (x.key, x.val)
proc `$`*[T](c: TCritBitTree[T]): string =
proc `$`*[T](c: CritBitTree[T]): string =
## turns `c` into a string representation. Example outputs:
## ``{keyA: value, keyB: value}``, ``{:}``
## If `T` is void the outputs look like:
@ -285,7 +287,7 @@ proc `$`*[T](c: TCritBitTree[T]): string =
result.add("}")
when isMainModule:
var r: TCritBitTree[void]
var r: CritBitTree[void]
r.incl "abc"
r.incl "xyz"
r.incl "def"

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -9,7 +9,7 @@
## The ``intsets`` module implements an efficient int set implemented as a
## sparse bit set.
## **Note**: Since Nimrod currently does not allow the assignment operator to
## **Note**: Since Nim currently does not allow the assignment operator to
## be overloaded, ``=`` for int sets performs some rather meaningless shallow
## copy; use ``assign`` to get a deep copy.
@ -17,7 +17,7 @@ import
os, hashes, math
type
TBitScalar = int
BitScalar = int
const
InitIntSetSize = 8 # must be a power of two!
@ -25,8 +25,8 @@ const
BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and
# divisible by 64
TrunkMask = BitsPerTrunk - 1
IntsPerTrunk = BitsPerTrunk div (sizeof(TBitScalar) * 8)
IntShift = 5 + ord(sizeof(TBitScalar) == 8) # 5 or 6, depending on int width
IntsPerTrunk = BitsPerTrunk div (sizeof(BitScalar) * 8)
IntShift = 5 + ord(sizeof(BitScalar) == 8) # 5 or 6, depending on int width
IntMask = 1 shl IntShift - 1
type
@ -34,15 +34,16 @@ type
TTrunk {.final.} = object
next: PTrunk # all nodes are connected with this pointer
key: int # start address at bit 0
bits: array[0..IntsPerTrunk - 1, TBitScalar] # a bit vector
bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector
TTrunkSeq = seq[PTrunk]
TIntSet* {.final.} = object ## an efficient set of 'int' implemented as a
## sparse bit set
IntSet* = object ## an efficient set of 'int' implemented as a sparse bit set
counter, max: int
head: PTrunk
data: TTrunkSeq
{.deprecated: [TIntSet: IntSet].}
proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -15,52 +15,58 @@ when not defined(nimhygiene):
{.pragma: dirty.}
type
TDoublyLinkedNode* {.pure,
final.}[T] = object ## a node a doubly linked list consists of
next*, prev*: ref TDoublyLinkedNode[T]
DoublyLinkedNodeObj*[T] = object ## a node a doubly linked list consists of
next*, prev*: ref DoublyLinkedNodeObj[T]
value*: T
PDoublyLinkedNode*[T] = ref TDoublyLinkedNode[T]
DoublyLinkedNode*[T] = ref DoublyLinkedNodeObj[T]
TSinglyLinkedNode* {.pure,
final.}[T] = object ## a node a singly linked list consists of
next*: ref TSinglyLinkedNode[T]
SinglyLinkedNodeObj*[T] = object ## a node a singly linked list consists of
next*: ref SinglyLinkedNodeObj[T]
value*: T
PSinglyLinkedNode*[T] = ref TSinglyLinkedNode[T]
SinglyLinkedNode*[T] = ref SinglyLinkedNodeObj[T]
TSinglyLinkedList* {.pure, final.}[T] = object ## a singly linked list
head*, tail*: PSinglyLinkedNode[T]
SinglyLinkedList*[T] = object ## a singly linked list
head*, tail*: SinglyLinkedNode[T]
TDoublyLinkedList* {.pure, final.}[T] = object ## a doubly linked list
head*, tail*: PDoublyLinkedNode[T]
DoublyLinkedList*[T] = object ## a doubly linked list
head*, tail*: DoublyLinkedNode[T]
TSinglyLinkedRing* {.pure, final.}[T] = object ## a singly linked ring
head*: PSinglyLinkedNode[T]
SinglyLinkedRing*[T] = object ## a singly linked ring
head*: SinglyLinkedNode[T]
TDoublyLinkedRing* {.pure, final.}[T] = object ## a doubly linked ring
head*: PDoublyLinkedNode[T]
DoublyLinkedRing*[T] = object ## a doubly linked ring
head*: DoublyLinkedNode[T]
proc initSinglyLinkedList*[T](): TSinglyLinkedList[T] =
{.deprecated: [TDoublyLinkedNode: DoublyLinkedNodeObj,
PDoublyLinkedNode: DoublyLinkedNode,
TSinglyLinkedNode: SinglyLinkedNodeObj,
PSinglyLinkedNode: SinglyLinkedNode,
TDoublyLinkedList: DoublyLinkedList,
TSinglyLinkedRing: SinglyLinkedRing,
TDoublyLinkedRing: DoublyLinkedRing].}
proc initSinglyLinkedList*[T](): SinglyLinkedList[T] =
## creates a new singly linked list that is empty.
discard
proc initDoublyLinkedList*[T](): TDoublyLinkedList[T] =
proc initDoublyLinkedList*[T](): DoublyLinkedList[T] =
## creates a new doubly linked list that is empty.
discard
proc initSinglyLinkedRing*[T](): TSinglyLinkedRing[T] =
proc initSinglyLinkedRing*[T](): SinglyLinkedRing[T] =
## creates a new singly linked ring that is empty.
discard
proc initDoublyLinkedRing*[T](): TDoublyLinkedRing[T] =
proc initDoublyLinkedRing*[T](): DoublyLinkedRing[T] =
## creates a new doubly linked ring that is empty.
discard
proc newDoublyLinkedNode*[T](value: T): PDoublyLinkedNode[T] =
proc newDoublyLinkedNode*[T](value: T): DoublyLinkedNode[T] =
## creates a new doubly linked node with the given `value`.
new(result)
result.value = value
proc newSinglyLinkedNode*[T](value: T): PSinglyLinkedNode[T] =
proc newSinglyLinkedNode*[T](value: T): SinglyLinkedNode[T] =
## creates a new singly linked node with the given `value`.
new(result)
result.value = value
@ -99,38 +105,38 @@ template findImpl() {.dirty.} =
for x in nodes(L):
if x.value == value: return x
iterator items*[T](L: TDoublyLinkedList[T]): T =
iterator items*[T](L: DoublyLinkedList[T]): T =
## yields every value of `L`.
itemsListImpl()
iterator items*[T](L: TSinglyLinkedList[T]): T =
iterator items*[T](L: SinglyLinkedList[T]): T =
## yields every value of `L`.
itemsListImpl()
iterator items*[T](L: TSinglyLinkedRing[T]): T =
iterator items*[T](L: SinglyLinkedRing[T]): T =
## yields every value of `L`.
itemsRingImpl()
iterator items*[T](L: TDoublyLinkedRing[T]): T =
iterator items*[T](L: DoublyLinkedRing[T]): T =
## yields every value of `L`.
itemsRingImpl()
iterator nodes*[T](L: TSinglyLinkedList[T]): PSinglyLinkedNode[T] =
iterator nodes*[T](L: SinglyLinkedList[T]): SinglyLinkedNode[T] =
## iterates over every node of `x`. Removing the current node from the
## list during traversal is supported.
nodesListImpl()
iterator nodes*[T](L: TDoublyLinkedList[T]): PDoublyLinkedNode[T] =
iterator nodes*[T](L: DoublyLinkedList[T]): DoublyLinkedNode[T] =
## iterates over every node of `x`. Removing the current node from the
## list during traversal is supported.
nodesListImpl()
iterator nodes*[T](L: TSinglyLinkedRing[T]): PSinglyLinkedNode[T] =
iterator nodes*[T](L: SinglyLinkedRing[T]): SinglyLinkedNode[T] =
## iterates over every node of `x`. Removing the current node from the
## list during traversal is supported.
nodesRingImpl()
iterator nodes*[T](L: TDoublyLinkedRing[T]): PDoublyLinkedNode[T] =
iterator nodes*[T](L: DoublyLinkedRing[T]): DoublyLinkedNode[T] =
## iterates over every node of `x`. Removing the current node from the
## list during traversal is supported.
nodesRingImpl()
@ -142,33 +148,33 @@ template dollarImpl() {.dirty.} =
result.add($x.value)
result.add("]")
proc `$`*[T](L: TSinglyLinkedList[T]): string =
proc `$`*[T](L: SinglyLinkedList[T]): string =
## turns a list into its string representation.
dollarImpl()
proc `$`*[T](L: TDoublyLinkedList[T]): string =
proc `$`*[T](L: DoublyLinkedList[T]): string =
## turns a list into its string representation.
dollarImpl()
proc `$`*[T](L: TSinglyLinkedRing[T]): string =
proc `$`*[T](L: SinglyLinkedRing[T]): string =
## turns a list into its string representation.
dollarImpl()
proc `$`*[T](L: TDoublyLinkedRing[T]): string =
proc `$`*[T](L: DoublyLinkedRing[T]): string =
## turns a list into its string representation.
dollarImpl()
proc find*[T](L: TSinglyLinkedList[T], value: T): PSinglyLinkedNode[T] =
proc find*[T](L: SinglyLinkedList[T], value: T): SinglyLinkedNode[T] =
## searches in the list for a value. Returns nil if the value does not
## exist.
findImpl()
proc find*[T](L: TDoublyLinkedList[T], value: T): PDoublyLinkedNode[T] =
proc find*[T](L: DoublyLinkedList[T], value: T): DoublyLinkedNode[T] =
## searches in the list for a value. Returns nil if the value does not
## exist.
findImpl()
proc find*[T](L: TSinglyLinkedRing[T], value: T): PSinglyLinkedNode[T] =
proc find*[T](L: SinglyLinkedRing[T], value: T): SinglyLinkedNode[T] =
## searches in the list for a value. Returns nil if the value does not
## exist.
findImpl()
@ -300,5 +306,3 @@ proc remove*[T](L: var TDoublyLinkedRing[T], n: PDoublyLinkedNode[T]) =
L.head = nil
else:
L.head = L.head.prev

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -12,13 +12,15 @@
import math
type
TQueue* {.pure, final.}[T] = object ## a queue
Queue*[T] = object ## a queue
data: seq[T]
rd, wr, count, mask: int
{.deprecated: [TQueue: Queue].}
proc initQueue*[T](initialSize=4): TQueue[T] =
## creates a new queue. `initialSize` needs to be a power of 2.
assert IsPowerOfTwo(initialSize)
assert isPowerOfTwo(initialSize)
result.mask = initialSize-1
newSeq(result.data, initialSize)

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2011 Alex Mitchell
#
# See the file "copying.txt", included in this
@ -31,7 +31,7 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
##
## Example:
##
## .. code-block:: nimrod
## .. code-block::
## let
## s1 = @[1, 2, 3]
## s2 = @[4, 5]
@ -50,7 +50,7 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
proc deduplicate*[T](seq1: seq[T]): seq[T] =
## Returns a new sequence without duplicates.
##
## .. code-block:: nimrod
## .. code-block::
## let
## dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
## dup2 = @["a", "a", "c", "d", "d"]
@ -69,7 +69,7 @@ proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
## fields `a` and `b`. If one sequence is shorter, the remaining items in the
## longer sequence are discarded. Example:
##
## .. code-block:: nimrod
## .. code-block::
## let
## short = @[1, 2, 3]
## long = @[6, 5, 4, 3, 2, 1]
@ -104,7 +104,7 @@ proc distribute*[T](s: seq[T], num: int, spread = true): seq[seq[T]] =
##
## Example:
##
## .. code-block:: nimrod
## .. code-block::
## let numbers = @[1, 2, 3, 4, 5, 6, 7]
## assert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
## assert numbers.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]]
@ -155,7 +155,7 @@ iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
##
## Example:
##
## .. code-block:: nimrod
## .. code-block::
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
## for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
## echo($n)
@ -169,7 +169,7 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
##
## Example:
##
## .. code-block:: nimrod
## .. code-block::
## let
## colors = @["red", "yellow", "black"]
## f1 = filter(colors, proc(x: string): bool = x.len < 6)
@ -184,7 +184,7 @@ proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.}) =
##
## Example:
##
## .. code-block:: nimrod
## .. code-block::
## var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
## keepIf(floats, proc(x: float): bool = x > 10)
## assert floats == @[13.0, 12.5, 10.1]
@ -202,7 +202,7 @@ proc delete*[T](s: var seq[T], first=0, last=0) =
##
## Example:
##
##.. code-block:: nimrod
##.. code-block::
## let outcome = @[1,1,1,1,1,1,1,1]
## var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
## dest.delete(3, 8)
@ -223,7 +223,7 @@ proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
##
## Example:
##
##.. code-block:: nimrod
##.. code-block::
## var dest = @[1,1,1,1,1,1,1,1]
## let
## src = @[2,2,2,2,2,2]
@ -254,7 +254,7 @@ template filterIt*(seq1, pred: expr): expr {.immediate.} =
## the ``it`` variable for testing, like: ``filterIt("abcxyz", it == 'x')``.
## Example:
##
## .. code-block:: nimrod
## .. code-block::
## let
## temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
## acceptable = filterIt(temperatures, it < 50 and it > -10)
@ -273,7 +273,7 @@ template keepItIf*(varSeq, pred: expr) =
## the ``it`` variable for testing, like: ``keepItIf("abcxyz", it == 'x')``.
## Example:
##
## .. code-block:: nimrod
## .. code-block::
## var candidates = @["foo", "bar", "baz", "foobar"]
## keepItIf(candidates, it.len == 3 and it[0] == 'b')
## assert candidates == @["bar", "baz"]
@ -292,7 +292,7 @@ template toSeq*(iter: expr): expr {.immediate.} =
##
## Example:
##
## .. code-block:: nimrod
## .. code-block::
## let
## numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
## odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
@ -318,18 +318,18 @@ template foldl*(sequence, operation: expr): expr =
## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) -
## 3). Example:
##
## .. code-block:: nimrod
## .. code-block::
## let
## numbers = @[5, 9, 11]
## addition = foldl(numbers, a + b)
## substraction = foldl(numbers, a - b)
## multiplication = foldl(numbers, a * b)
## words = @["nim", "rod", "is", "cool"]
## words = @["nim", "is", "cool"]
## concatenation = foldl(words, a & b)
## assert addition == 25, "Addition is (((5)+9)+11)"
## assert substraction == -15, "Substraction is (((5)-9)-11)"
## assert multiplication == 495, "Multiplication is (((5)*9)*11)"
## assert concatenation == "nimrodiscool"
## assert concatenation == "nimiscool"
assert sequence.len > 0, "Can't fold empty sequences"
var result {.gensym.}: type(sequence[0])
result = sequence[0]
@ -354,18 +354,18 @@ template foldr*(sequence, operation: expr): expr =
## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 -
## (3))). Example:
##
## .. code-block:: nimrod
## .. code-block::
## let
## numbers = @[5, 9, 11]
## addition = foldr(numbers, a + b)
## substraction = foldr(numbers, a - b)
## multiplication = foldr(numbers, a * b)
## words = @["nim", "rod", "is", "cool"]
## words = @["nim", "is", "cool"]
## concatenation = foldr(words, a & b)
## assert addition == 25, "Addition is (5+(9+(11)))"
## assert substraction == 7, "Substraction is (5-(9-(11)))"
## assert multiplication == 495, "Multiplication is (5*(9*(11)))"
## assert concatenation == "nimrodiscool"
## assert concatenation == "nimiscool"
assert sequence.len > 0, "Can't fold empty sequences"
var result {.gensym.}: type(sequence[0])
result = sequence[sequence.len - 1]
@ -384,7 +384,7 @@ template mapIt*(seq1, typ, pred: expr): expr =
## since the new returned sequence can have a different type than the
## original. Example:
##
## .. code-block:: nimrod
## .. code-block::
## let
## nums = @[1, 2, 3, 4]
## strings = nums.mapIt(string, $(4 * it))
@ -401,7 +401,7 @@ template mapIt*(varSeq, pred: expr) =
## expression. The expression has to return the same type as the sequence you
## are mutating. Example:
##
## .. code-block:: nimrod
## .. code-block::
## var nums = @[1, 2, 3, 4]
## nums.mapIt(it * 3)
## assert nums[0] + nums[3] == 15
@ -412,7 +412,7 @@ template mapIt*(varSeq, pred: expr) =
template newSeqWith*(len: int, init: expr): expr =
## creates a new sequence, calling `init` to initialize each value. Example:
##
## .. code-block:: nimrod
## .. code-block::
## var seq2D = newSeqWith(20, newSeq[bool](10))
## seq2D[0][0] = true
## seq2D[1][0] = true
@ -503,12 +503,12 @@ when isMainModule:
addition = foldl(numbers, a + b)
substraction = foldl(numbers, a - b)
multiplication = foldl(numbers, a * b)
words = @["nim", "rod", "is", "cool"]
words = @["nim", "is", "cool"]
concatenation = foldl(words, a & b)
assert addition == 25, "Addition is (((5)+9)+11)"
assert substraction == -15, "Substraction is (((5)-9)-11)"
assert multiplication == 495, "Multiplication is (((5)*9)*11)"
assert concatenation == "nimrodiscool"
assert concatenation == "nimiscool"
block: # foldr tests
let
@ -516,12 +516,12 @@ when isMainModule:
addition = foldr(numbers, a + b)
substraction = foldr(numbers, a - b)
multiplication = foldr(numbers, a * b)
words = @["nim", "rod", "is", "cool"]
words = @["nim", "is", "cool"]
concatenation = foldr(words, a & b)
assert addition == 25, "Addition is (5+(9+(11)))"
assert substraction == 7, "Substraction is (5-(9-(11)))"
assert multiplication == 495, "Multiplication is (5*(9*(11)))"
assert concatenation == "nimrodiscool"
assert concatenation == "nimiscool"
block: # delete tests
let outcome = @[1,1,1,1,1,1,1,1]

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -24,17 +24,19 @@ when not defined(nimhygiene):
{.pragma: dirty.}
type
TSlotEnum = enum seEmpty, seFilled, seDeleted
TKeyValuePair[A] = tuple[slot: TSlotEnum, key: A]
TKeyValuePairSeq[A] = seq[TKeyValuePair[A]]
TSet* {.final, myShallow.}[A] = object ## \
SlotEnum = enum seEmpty, seFilled, seDeleted
KeyValuePair[A] = tuple[slot: SlotEnum, key: A]
KeyValuePairSeq[A] = seq[KeyValuePair[A]]
HashSet* {.myShallow.}[A] = object ## \
## A generic hash set.
##
## Use `init() <#init,TSet[A],int>`_ or `initSet[type]() <#initSet>`_
## Use `init() <#init,HashSet[A],int>`_ or `initSet[type]() <#initSet>`_
## before calling other procs on it.
data: TKeyValuePairSeq[A]
data: KeyValuePairSeq[A]
counter: int
{.deprecated: [TSet: HashSet].}
proc isValid*[A](s: TSet[A]): bool =
## Returns `true` if the set has been initialized with `initSet <#initSet>`_.
##
@ -43,7 +45,7 @@ proc isValid*[A](s: TSet[A]): bool =
## your own procs to verify that sets passed to your procs are correctly
## initialized. Example:
##
## .. code-block :: nimrod
## .. code-block ::
## proc savePreferences(options: TSet[string]) =
## assert options.isValid, "Pass an initialized set!"
## # Do stuff here, may crash in release builds!
@ -490,19 +492,20 @@ proc map*[A, B](data: TSet[A], op: proc (x: A): B {.closure.}): TSet[B] =
# ------------------------------ ordered set ------------------------------
type
TOrderedKeyValuePair[A] = tuple[
slot: TSlotEnum, next: int, key: A]
TOrderedKeyValuePairSeq[A] = seq[TOrderedKeyValuePair[A]]
TOrderedSet* {.
final, myShallow.}[A] = object ## \
OrderedKeyValuePair[A] = tuple[
slot: SlotEnum, next: int, key: A]
OrderedKeyValuePairSeq[A] = seq[OrderedKeyValuePair[A]]
OrderedSet* {.myShallow.}[A] = object ## \
## A generic hash set that remembers insertion order.
##
## Use `init() <#init,TOrderedSet[A],int>`_ or `initOrderedSet[type]()
## Use `init() <#init,OrderedSet[A],int>`_ or `initOrderedSet[type]()
## <#initOrderedSet>`_ before calling other procs on it.
data: TOrderedKeyValuePairSeq[A]
counter, first, last: int
proc isValid*[A](s: TOrderedSet[A]): bool =
{.deprecated: [TOrderedSet: OrderedSet].}
proc isValid*[A](s: OrderedSet[A]): bool =
## Returns `true` if the ordered set has been initialized with `initSet
## <#initOrderedSet>`_.
##
@ -511,13 +514,13 @@ proc isValid*[A](s: TOrderedSet[A]): bool =
## in your own procs to verify that ordered sets passed to your procs are
## correctly initialized. Example:
##
## .. code-block :: nimrod
## .. code-block::
## proc saveTarotCards(cards: TOrderedSet[int]) =
## assert cards.isValid, "Pass an initialized set!"
## # Do stuff here, may crash in release builds!
result = not s.data.isNil
proc len*[A](s: TOrderedSet[A]): int {.inline.} =
proc len*[A](s: OrderedSet[A]): int {.inline.} =
## Returns the number of keys in `s`.
##
## Due to an implementation detail you can call this proc on variables which
@ -734,14 +737,14 @@ proc `==`*[A](s, t: TOrderedSet[A]): bool =
proc testModule() =
## Internal micro test to validate docstrings and such.
block isValidTest:
var options: TSet[string]
var options: HashSet[string]
proc savePreferences(options: TSet[string]) =
assert options.isValid, "Pass an initialized set!"
options = initSet[string]()
options.savePreferences
block lenTest:
var values: TSet[int]
var values: HashSet[int]
assert(not values.isValid)
assert values.len == 0
assert values.card == 0
@ -835,14 +838,14 @@ proc testModule() =
assert b == toSet(["1", "2", "3"])
block isValidTest:
var cards: TOrderedSet[string]
var cards: OrderedSet[string]
proc saveTarotCards(cards: TOrderedSet[string]) =
assert cards.isValid, "Pass an initialized set!"
cards = initOrderedSet[string]()
cards.saveTarotCards
block lenTest:
var values: TOrderedSet[int]
var values: OrderedSet[int]
assert(not values.isValid)
assert values.len == 0
assert values.card == 0
@ -879,7 +882,7 @@ proc testModule() =
assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
block initBlocks:
var a: TOrderedSet[int]
var a: OrderedSet[int]
a.init(4)
a.incl(2)
a.init

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -28,7 +28,7 @@
## you add such a proc for your custom type everything will work. See this
## example:
##
## .. code-block:: nimrod
## .. code-block::
## type
## Person = object
## firstName, lastName: string
@ -61,13 +61,15 @@ import
{.pragma: myShallow.}
type
TSlotEnum = enum seEmpty, seFilled, seDeleted
TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B]
TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]]
TTable* {.final, myShallow.}[A, B] = object ## generic hash table
data: TKeyValuePairSeq[A, B]
SlotEnum = enum seEmpty, seFilled, seDeleted
KeyValuePair[A, B] = tuple[slot: SlotEnum, key: A, val: B]
KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]]
Table* {.myShallow.}[A, B] = object ## generic hash table
data: KeyValuePairSeq[A, B]
counter: int
PTable*[A,B] = ref TTable[A, B]
TableRef*[A,B] = ref Table[A, B]
{.deprecated: [TTable: Table, PTable: TableRef].}
when not defined(nimhygiene):
{.pragma: dirty.}
@ -158,12 +160,12 @@ proc hasKey*[A, B](t: TTable[A, B], key: A): bool =
## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0
proc rawInsert[A, B](t: var TTable[A, B], data: var TKeyValuePairSeq[A, B],
proc rawInsert[A, B](t: var TTable[A, B], data: var KeyValuePairSeq[A, B],
key: A, val: B) =
rawInsertImpl()
proc enlarge[A, B](t: var TTable[A, B]) =
var n: TKeyValuePairSeq[A, B]
var n: KeyValuePairSeq[A, B]
newSeq(n, len(t.data) * growthFactor)
for i in countup(0, high(t.data)):
if t.data[i].slot == seFilled: rawInsert(t, n, t.data[i].key, t.data[i].val)
@ -347,14 +349,16 @@ proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): PTable[C, B] =
# ------------------------------ ordered table ------------------------------
type
TOrderedKeyValuePair[A, B] = tuple[
slot: TSlotEnum, next: int, key: A, val: B]
TOrderedKeyValuePairSeq[A, B] = seq[TOrderedKeyValuePair[A, B]]
TOrderedTable* {.
final, myShallow.}[A, B] = object ## table that remembers insertion order
data: TOrderedKeyValuePairSeq[A, B]
OrderedKeyValuePair[A, B] = tuple[
slot: SlotEnum, next: int, key: A, val: B]
OrderedKeyValuePairSeq[A, B] = seq[OrderedKeyValuePair[A, B]]
OrderedTable* {.
myShallow.}[A, B] = object ## table that remembers insertion order
data: OrderedKeyValuePairSeq[A, B]
counter, first, last: int
POrderedTable*[A, B] = ref TOrderedTable[A, B]
OrderedTableRef*[A, B] = ref OrderedTable[A, B]
{.deprecated: [TOrderedTable: OrderedTable, POrderedTable: OrderedTableRef].}
proc len*[A, B](t: TOrderedTable[A, B]): int {.inline.} =
## returns the number of keys in `t`.
@ -608,11 +612,13 @@ proc sort*[A, B](t: POrderedTable[A, B],
# ------------------------------ count tables -------------------------------
type
TCountTable* {.final, myShallow.}[
CountTable* {.myShallow.}[
A] = object ## table that counts the number of each key
data: seq[tuple[key: A, val: int]]
counter: int
PCountTable*[A] = ref TCountTable[A]
CountTableRef*[A] = ref CountTable[A]
{.deprecated: [TCountTable: CountTable, PCountTable: CountTableRef].}
proc len*[A](t: TCountTable[A]): int =
## returns the number of keys in `t`.

View file

@ -1,5 +1,5 @@
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -12,18 +12,20 @@
import strutils
type
TColor* = distinct int ## a color stored as RGB
Color* = distinct int ## a color stored as RGB
proc `==` *(a, b: TColor): bool {.borrow.}
{.deprecated: [TColor: Color].}
proc `==` *(a, b: Color): bool {.borrow.}
## compares two colors.
template extract(a: TColor, r, g, b: expr) {.immediate.}=
template extract(a: Color, r, g, b: expr) {.immediate.}=
var r = a.int shr 16 and 0xff
var g = a.int shr 8 and 0xff
var b = a.int and 0xff
template rawRGB(r, g, b: int): expr =
TColor(r shl 16 or g shl 8 or b)
Color(r shl 16 or g shl 8 or b)
template colorOp(op: expr) {.immediate.} =
extract(a, ar, ag, ab)
@ -38,23 +40,23 @@ proc satMinus(a, b: int): int {.inline.} =
result = a -% b
if result < 0: result = 0
proc `+`*(a, b: TColor): TColor =
proc `+`*(a, b: Color): Color =
## adds two colors: This uses saturated artithmetic, so that each color
## component cannot overflow (255 is used as a maximum).
colorOp(satPlus)
proc `-`*(a, b: TColor): TColor =
proc `-`*(a, b: Color): Color =
## substracts two colors: This uses saturated artithmetic, so that each color
## component cannot overflow (255 is used as a maximum).
colorOp(satMinus)
proc extractRGB*(a: TColor): tuple[r, g, b: range[0..255]] =
proc extractRGB*(a: Color): tuple[r, g, b: range[0..255]] =
## extracts the red/green/blue components of the color `a`.
result.r = a.int shr 16 and 0xff
result.g = a.int shr 8 and 0xff
result.b = a.int and 0xff
proc intensity*(a: TColor, f: float): TColor =
proc intensity*(a: Color, f: float): Color =
## returns `a` with intensity `f`. `f` should be a float from 0.0 (completely
## dark) to 1.0 (full color intensity).
var r = toInt(toFloat(a.int shr 16 and 0xff) * f)
@ -65,7 +67,7 @@ proc intensity*(a: TColor, f: float): TColor =
if b >% 255: b = 255
result = rawRGB(r, g, b)
template mix*(a, b: TColor, fn: expr): expr =
template mix*(a, b: Color, fn: expr): expr =
## uses `fn` to mix the colors `a` and `b`. `fn` is invoked for each component
## R, G, and B. This is a template because `fn` should be inlined and the
## compiler cannot inline proc pointers yet. If `fn`'s result is not in the
@ -84,146 +86,146 @@ template mix*(a, b: TColor, fn: expr): expr =
const
colAliceBlue* = TColor(0xF0F8FF)
colAntiqueWhite* = TColor(0xFAEBD7)
colAqua* = TColor(0x00FFFF)
colAquamarine* = TColor(0x7FFFD4)
colAzure* = TColor(0xF0FFFF)
colBeige* = TColor(0xF5F5DC)
colBisque* = TColor(0xFFE4C4)
colBlack* = TColor(0x000000)
colBlanchedAlmond* = TColor(0xFFEBCD)
colBlue* = TColor(0x0000FF)
colBlueViolet* = TColor(0x8A2BE2)
colBrown* = TColor(0xA52A2A)
colBurlyWood* = TColor(0xDEB887)
colCadetBlue* = TColor(0x5F9EA0)
colChartreuse* = TColor(0x7FFF00)
colChocolate* = TColor(0xD2691E)
colCoral* = TColor(0xFF7F50)
colCornflowerBlue* = TColor(0x6495ED)
colCornsilk* = TColor(0xFFF8DC)
colCrimson* = TColor(0xDC143C)
colCyan* = TColor(0x00FFFF)
colDarkBlue* = TColor(0x00008B)
colDarkCyan* = TColor(0x008B8B)
colDarkGoldenRod* = TColor(0xB8860B)
colDarkGray* = TColor(0xA9A9A9)
colDarkGreen* = TColor(0x006400)
colDarkKhaki* = TColor(0xBDB76B)
colDarkMagenta* = TColor(0x8B008B)
colDarkOliveGreen* = TColor(0x556B2F)
colDarkorange* = TColor(0xFF8C00)
colDarkOrchid* = TColor(0x9932CC)
colDarkRed* = TColor(0x8B0000)
colDarkSalmon* = TColor(0xE9967A)
colDarkSeaGreen* = TColor(0x8FBC8F)
colDarkSlateBlue* = TColor(0x483D8B)
colDarkSlateGray* = TColor(0x2F4F4F)
colDarkTurquoise* = TColor(0x00CED1)
colDarkViolet* = TColor(0x9400D3)
colDeepPink* = TColor(0xFF1493)
colDeepSkyBlue* = TColor(0x00BFFF)
colDimGray* = TColor(0x696969)
colDodgerBlue* = TColor(0x1E90FF)
colFireBrick* = TColor(0xB22222)
colFloralWhite* = TColor(0xFFFAF0)
colForestGreen* = TColor(0x228B22)
colFuchsia* = TColor(0xFF00FF)
colGainsboro* = TColor(0xDCDCDC)
colGhostWhite* = TColor(0xF8F8FF)
colGold* = TColor(0xFFD700)
colGoldenRod* = TColor(0xDAA520)
colGray* = TColor(0x808080)
colGreen* = TColor(0x008000)
colGreenYellow* = TColor(0xADFF2F)
colHoneyDew* = TColor(0xF0FFF0)
colHotPink* = TColor(0xFF69B4)
colIndianRed* = TColor(0xCD5C5C)
colIndigo* = TColor(0x4B0082)
colIvory* = TColor(0xFFFFF0)
colKhaki* = TColor(0xF0E68C)
colLavender* = TColor(0xE6E6FA)
colLavenderBlush* = TColor(0xFFF0F5)
colLawnGreen* = TColor(0x7CFC00)
colLemonChiffon* = TColor(0xFFFACD)
colLightBlue* = TColor(0xADD8E6)
colLightCoral* = TColor(0xF08080)
colLightCyan* = TColor(0xE0FFFF)
colLightGoldenRodYellow* = TColor(0xFAFAD2)
colLightGrey* = TColor(0xD3D3D3)
colLightGreen* = TColor(0x90EE90)
colLightPink* = TColor(0xFFB6C1)
colLightSalmon* = TColor(0xFFA07A)
colLightSeaGreen* = TColor(0x20B2AA)
colLightSkyBlue* = TColor(0x87CEFA)
colLightSlateGray* = TColor(0x778899)
colLightSteelBlue* = TColor(0xB0C4DE)
colLightYellow* = TColor(0xFFFFE0)
colLime* = TColor(0x00FF00)
colLimeGreen* = TColor(0x32CD32)
colLinen* = TColor(0xFAF0E6)
colMagenta* = TColor(0xFF00FF)
colMaroon* = TColor(0x800000)
colMediumAquaMarine* = TColor(0x66CDAA)
colMediumBlue* = TColor(0x0000CD)
colMediumOrchid* = TColor(0xBA55D3)
colMediumPurple* = TColor(0x9370D8)
colMediumSeaGreen* = TColor(0x3CB371)
colMediumSlateBlue* = TColor(0x7B68EE)
colMediumSpringGreen* = TColor(0x00FA9A)
colMediumTurquoise* = TColor(0x48D1CC)
colMediumVioletRed* = TColor(0xC71585)
colMidnightBlue* = TColor(0x191970)
colMintCream* = TColor(0xF5FFFA)
colMistyRose* = TColor(0xFFE4E1)
colMoccasin* = TColor(0xFFE4B5)
colNavajoWhite* = TColor(0xFFDEAD)
colNavy* = TColor(0x000080)
colOldLace* = TColor(0xFDF5E6)
colOlive* = TColor(0x808000)
colOliveDrab* = TColor(0x6B8E23)
colOrange* = TColor(0xFFA500)
colOrangeRed* = TColor(0xFF4500)
colOrchid* = TColor(0xDA70D6)
colPaleGoldenRod* = TColor(0xEEE8AA)
colPaleGreen* = TColor(0x98FB98)
colPaleTurquoise* = TColor(0xAFEEEE)
colPaleVioletRed* = TColor(0xD87093)
colPapayaWhip* = TColor(0xFFEFD5)
colPeachPuff* = TColor(0xFFDAB9)
colPeru* = TColor(0xCD853F)
colPink* = TColor(0xFFC0CB)
colPlum* = TColor(0xDDA0DD)
colPowderBlue* = TColor(0xB0E0E6)
colPurple* = TColor(0x800080)
colRed* = TColor(0xFF0000)
colRosyBrown* = TColor(0xBC8F8F)
colRoyalBlue* = TColor(0x4169E1)
colSaddleBrown* = TColor(0x8B4513)
colSalmon* = TColor(0xFA8072)
colSandyBrown* = TColor(0xF4A460)
colSeaGreen* = TColor(0x2E8B57)
colSeaShell* = TColor(0xFFF5EE)
colSienna* = TColor(0xA0522D)
colSilver* = TColor(0xC0C0C0)
colSkyBlue* = TColor(0x87CEEB)
colSlateBlue* = TColor(0x6A5ACD)
colSlateGray* = TColor(0x708090)
colSnow* = TColor(0xFFFAFA)
colSpringGreen* = TColor(0x00FF7F)
colSteelBlue* = TColor(0x4682B4)
colTan* = TColor(0xD2B48C)
colTeal* = TColor(0x008080)
colThistle* = TColor(0xD8BFD8)
colTomato* = TColor(0xFF6347)
colTurquoise* = TColor(0x40E0D0)
colViolet* = TColor(0xEE82EE)
colWheat* = TColor(0xF5DEB3)
colWhite* = TColor(0xFFFFFF)
colWhiteSmoke* = TColor(0xF5F5F5)
colYellow* = TColor(0xFFFF00)
colYellowGreen* = TColor(0x9ACD32)
colAliceBlue* = Color(0xF0F8FF)
colAntiqueWhite* = Color(0xFAEBD7)
colAqua* = Color(0x00FFFF)
colAquamarine* = Color(0x7FFFD4)
colAzure* = Color(0xF0FFFF)
colBeige* = Color(0xF5F5DC)
colBisque* = Color(0xFFE4C4)
colBlack* = Color(0x000000)
colBlanchedAlmond* = Color(0xFFEBCD)
colBlue* = Color(0x0000FF)
colBlueViolet* = Color(0x8A2BE2)
colBrown* = Color(0xA52A2A)
colBurlyWood* = Color(0xDEB887)
colCadetBlue* = Color(0x5F9EA0)
colChartreuse* = Color(0x7FFF00)
colChocolate* = Color(0xD2691E)
colCoral* = Color(0xFF7F50)
colCornflowerBlue* = Color(0x6495ED)
colCornsilk* = Color(0xFFF8DC)
colCrimson* = Color(0xDC143C)
colCyan* = Color(0x00FFFF)
colDarkBlue* = Color(0x00008B)
colDarkCyan* = Color(0x008B8B)
colDarkGoldenRod* = Color(0xB8860B)
colDarkGray* = Color(0xA9A9A9)
colDarkGreen* = Color(0x006400)
colDarkKhaki* = Color(0xBDB76B)
colDarkMagenta* = Color(0x8B008B)
colDarkOliveGreen* = Color(0x556B2F)
colDarkorange* = Color(0xFF8C00)
colDarkOrchid* = Color(0x9932CC)
colDarkRed* = Color(0x8B0000)
colDarkSalmon* = Color(0xE9967A)
colDarkSeaGreen* = Color(0x8FBC8F)
colDarkSlateBlue* = Color(0x483D8B)
colDarkSlateGray* = Color(0x2F4F4F)
colDarkTurquoise* = Color(0x00CED1)
colDarkViolet* = Color(0x9400D3)
colDeepPink* = Color(0xFF1493)
colDeepSkyBlue* = Color(0x00BFFF)
colDimGray* = Color(0x696969)
colDodgerBlue* = Color(0x1E90FF)
colFireBrick* = Color(0xB22222)
colFloralWhite* = Color(0xFFFAF0)
colForestGreen* = Color(0x228B22)
colFuchsia* = Color(0xFF00FF)
colGainsboro* = Color(0xDCDCDC)
colGhostWhite* = Color(0xF8F8FF)
colGold* = Color(0xFFD700)
colGoldenRod* = Color(0xDAA520)
colGray* = Color(0x808080)
colGreen* = Color(0x008000)
colGreenYellow* = Color(0xADFF2F)
colHoneyDew* = Color(0xF0FFF0)
colHotPink* = Color(0xFF69B4)
colIndianRed* = Color(0xCD5C5C)
colIndigo* = Color(0x4B0082)
colIvory* = Color(0xFFFFF0)
colKhaki* = Color(0xF0E68C)
colLavender* = Color(0xE6E6FA)
colLavenderBlush* = Color(0xFFF0F5)
colLawnGreen* = Color(0x7CFC00)
colLemonChiffon* = Color(0xFFFACD)
colLightBlue* = Color(0xADD8E6)
colLightCoral* = Color(0xF08080)
colLightCyan* = Color(0xE0FFFF)
colLightGoldenRodYellow* = Color(0xFAFAD2)
colLightGrey* = Color(0xD3D3D3)
colLightGreen* = Color(0x90EE90)
colLightPink* = Color(0xFFB6C1)
colLightSalmon* = Color(0xFFA07A)
colLightSeaGreen* = Color(0x20B2AA)
colLightSkyBlue* = Color(0x87CEFA)
colLightSlateGray* = Color(0x778899)
colLightSteelBlue* = Color(0xB0C4DE)
colLightYellow* = Color(0xFFFFE0)
colLime* = Color(0x00FF00)
colLimeGreen* = Color(0x32CD32)
colLinen* = Color(0xFAF0E6)
colMagenta* = Color(0xFF00FF)
colMaroon* = Color(0x800000)
colMediumAquaMarine* = Color(0x66CDAA)
colMediumBlue* = Color(0x0000CD)
colMediumOrchid* = Color(0xBA55D3)
colMediumPurple* = Color(0x9370D8)
colMediumSeaGreen* = Color(0x3CB371)
colMediumSlateBlue* = Color(0x7B68EE)
colMediumSpringGreen* = Color(0x00FA9A)
colMediumTurquoise* = Color(0x48D1CC)
colMediumVioletRed* = Color(0xC71585)
colMidnightBlue* = Color(0x191970)
colMintCream* = Color(0xF5FFFA)
colMistyRose* = Color(0xFFE4E1)
colMoccasin* = Color(0xFFE4B5)
colNavajoWhite* = Color(0xFFDEAD)
colNavy* = Color(0x000080)
colOldLace* = Color(0xFDF5E6)
colOlive* = Color(0x808000)
colOliveDrab* = Color(0x6B8E23)
colOrange* = Color(0xFFA500)
colOrangeRed* = Color(0xFF4500)
colOrchid* = Color(0xDA70D6)
colPaleGoldenRod* = Color(0xEEE8AA)
colPaleGreen* = Color(0x98FB98)
colPaleTurquoise* = Color(0xAFEEEE)
colPaleVioletRed* = Color(0xD87093)
colPapayaWhip* = Color(0xFFEFD5)
colPeachPuff* = Color(0xFFDAB9)
colPeru* = Color(0xCD853F)
colPink* = Color(0xFFC0CB)
colPlum* = Color(0xDDA0DD)
colPowderBlue* = Color(0xB0E0E6)
colPurple* = Color(0x800080)
colRed* = Color(0xFF0000)
colRosyBrown* = Color(0xBC8F8F)
colRoyalBlue* = Color(0x4169E1)
colSaddleBrown* = Color(0x8B4513)
colSalmon* = Color(0xFA8072)
colSandyBrown* = Color(0xF4A460)
colSeaGreen* = Color(0x2E8B57)
colSeaShell* = Color(0xFFF5EE)
colSienna* = Color(0xA0522D)
colSilver* = Color(0xC0C0C0)
colSkyBlue* = Color(0x87CEEB)
colSlateBlue* = Color(0x6A5ACD)
colSlateGray* = Color(0x708090)
colSnow* = Color(0xFFFAFA)
colSpringGreen* = Color(0x00FF7F)
colSteelBlue* = Color(0x4682B4)
colTan* = Color(0xD2B48C)
colTeal* = Color(0x008080)
colThistle* = Color(0xD8BFD8)
colTomato* = Color(0xFF6347)
colTurquoise* = Color(0x40E0D0)
colViolet* = Color(0xEE82EE)
colWheat* = Color(0xF5DEB3)
colWhite* = Color(0xFFFFFF)
colWhiteSmoke* = Color(0xF5F5F5)
colYellow* = Color(0xFFFF00)
colYellowGreen* = Color(0x9ACD32)
colorNames = [
("aliceblue", colAliceBlue),
@ -367,11 +369,11 @@ const
("yellow", colYellow),
("yellowgreen", colYellowGreen)]
proc `$`*(c: TColor): string =
proc `$`*(c: Color): string =
## converts a color into its textual representation. Example: ``#00FF00``.
result = '#' & toHex(int(c), 6)
proc binaryStrSearch(x: openarray[tuple[name: string, col: TColor]],
proc binaryStrSearch(x: openArray[tuple[name: string, col: Color]],
y: string): int =
var a = 0
var b = len(x) - 1
@ -383,14 +385,14 @@ proc binaryStrSearch(x: openarray[tuple[name: string, col: TColor]],
else: return mid
result = - 1
proc parseColor*(name: string): TColor =
proc parseColor*(name: string): Color =
## parses `name` to a color value. If no valid color could be
## parsed ``EInvalidValue`` is raised.
if name[0] == '#':
result = TColor(parseHexInt(name))
result = Color(parseHexInt(name))
else:
var idx = binaryStrSearch(colorNames, name)
if idx < 0: raise newException(EInvalidValue, "unkown color: " & name)
if idx < 0: raise newException(ValueError, "unkown color: " & name)
result = colorNames[idx][1]
proc isColor*(name: string): bool =
@ -403,7 +405,7 @@ proc isColor*(name: string): bool =
else:
result = binaryStrSearch(colorNames, name) >= 0
proc rgb*(r, g, b: range[0..255]): TColor =
proc rgb*(r, g, b: range[0..255]): Color =
## constructs a color from RGB values.
result = rawRGB(r, g, b)

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -25,9 +25,11 @@ const
type
TComplex* = tuple[re, im: float]
Complex* = tuple[re, im: float]
## a complex number, consisting of a real and an imaginary part
{.deprecated: [TComplex: Complex].}
proc `==` *(x, y: TComplex): bool =
## Compare two complex numbers `x` and `y` for equality.
result = x.re == y.re and x.im == y.im

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,13 +1,13 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Implements Nimrod's 'spawn'.
## Implements Nim's 'spawn'.
when not compileOption("threads"):
{.error: "Threadpool requires --threads:on option.".}

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -11,7 +11,7 @@
import strtabs, times
proc parseCookies*(s: string): PStringTable =
proc parseCookies*(s: string): StringTableRef =
## parses cookies into a string table.
result = newStringTable(modeCaseInsensitive)
var i = 0
@ -39,7 +39,7 @@ proc setCookie*(key, value: string, domain = "", path = "",
if path != "": result.add("; Path=" & path)
if expires != "": result.add("; Expires=" & expires)
proc setCookie*(key, value: string, expires: TTimeInfo,
proc setCookie*(key, value: string, expires: TimeInfo,
domain = "", path = "", noName = false): string =
## Creates a command in the format of
## ``Set-Cookie: key=value; Domain=...; ...``
@ -50,7 +50,7 @@ proc setCookie*(key, value: string, expires: TTimeInfo,
format(expires, "ddd',' dd MMM yyyy HH:mm:ss 'UTC'"), noName)
when isMainModule:
var tim = TTime(int(getTime()) + 76 * (60 * 60 * 24))
var tim = Time(int(getTime()) + 76 * (60 * 60 * 24))
echo(setCookie("test", "value", tim.getGMTime()))

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -12,7 +12,9 @@
## Windows ``LoadLibrary``.
type
TLibHandle* = pointer ## a handle to a dynamically loaded library
LibHandle* = pointer ## a handle to a dynamically loaded library
{.deprecated: [TLibHandle: LibHandle].}
proc loadLib*(path: string, global_symbols=false): TLibHandle
## loads a library from `path`. Returns nil if the library could not

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -14,18 +14,20 @@ import os, parseutils, strutils
when not defined(windows):
type
TConverter = object
PConverter* = ptr TConverter ## can convert between two character sets
ConverterObj = object
EncodingConverter* = ptr ConverterObj ## can convert between two character sets
else:
type
TCodePage = distinct int32
PConverter* = object
dest, src: TCodePage
CodePage = distinct int32
EncodingConverter* = object
dest, src: CodePage
type
EInvalidEncoding* = object of EInvalidValue ## exception that is raised
## for encoding errors
EncodingError* = object of ValueError ## exception that is raised
## for encoding errors
{.deprecated: [EInvalidEncoding: EncodingError, PConverter: EncodingConverter].}
when defined(windows):
proc eqEncodingNames(a, b: string): bool =
@ -214,26 +216,26 @@ when defined(windows):
defaultChar: array[0..1, char]
leadByte: array[0..12-1, char]
proc getCPInfo(codePage: TCodePage, lpCPInfo: var TCpInfo): int32 {.
proc getCPInfo(codePage: CodePage, lpCPInfo: var TCpInfo): int32 {.
stdcall, importc: "GetCPInfo", dynlib: "kernel32".}
proc nameToCodePage(name: string): TCodePage =
proc nameToCodePage(name: string): CodePage =
var nameAsInt: int
if parseInt(name, nameAsInt) == 0: nameAsInt = -1
for no, na in items(winEncodings):
if no == nameAsInt or eqEncodingNames(na, name): return TCodePage(no)
result = TCodePage(-1)
if no == nameAsInt or eqEncodingNames(na, name): return CodePage(no)
result = CodePage(-1)
proc codePageToName(c: TCodePage): string =
proc codePageToName(c: CodePage): string =
for no, na in items(winEncodings):
if no == int(c):
return if na.len != 0: na else: $no
result = ""
proc getACP(): TCodePage {.stdcall, importc: "GetACP", dynlib: "kernel32".}
proc getACP(): CodePage {.stdcall, importc: "GetACP", dynlib: "kernel32".}
proc multiByteToWideChar(
codePage: TCodePage,
codePage: CodePage,
dwFlags: int32,
lpMultiByteStr: cstring,
cbMultiByte: cint,
@ -242,7 +244,7 @@ when defined(windows):
stdcall, importc: "MultiByteToWideChar", dynlib: "kernel32".}
proc wideCharToMultiByte(
codePage: TCodePage,
codePage: CodePage,
dwFlags: int32,
lpWideCharStr: cstring,
cchWideChar: cint,

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2011 Alex Mitchell
#
# See the file "copying.txt", included in this
@ -14,10 +14,10 @@
## it was inspired by Python's PyEE module. There are two ways you can use
## events: one is a python-inspired way; the other is more of a C-style way.
##
## .. code-block:: Nimrod
## .. code-block:: Nim
## var ee = initEventEmitter()
## var genericargs: TEventArgs
## proc handleevent(e: TEventArgs) =
## var genericargs: EventArgs
## proc handleevent(e: EventArgs) =
## echo("Handled!")
##
## # Python way
@ -27,21 +27,24 @@
## # C/Java way
## # Declare a type
## type
## TSomeObject = object of TObject
## SomeEvent: TEventHandler
## var myobj: TSomeObject
## SomeObject = object of RootObj
## SomeEvent: EventHandler
## var myobj: SomeObject
## myobj.SomeEvent = initEventHandler("SomeEvent")
## myobj.SomeEvent.addHandler(handleevent)
## ee.emit(myobj.SomeEvent, genericargs)
type
TEventArgs* = object of TObject ## Base object for event arguments that are passed to callback functions.
TEventHandler* = tuple[name: string, handlers: seq[proc(e:TEventArgs) {.closure.}]] ## An eventhandler for an event.
EventArgs* = object of RootObj ## Base object for event arguments that are passed to callback functions.
EventHandler* = tuple[name: string, handlers: seq[proc(e: EventArgs) {.closure.}]] ## An eventhandler for an event.
type
TEventEmitter* = object {.pure, final.} ## An object that fires events and holds event handlers for an object.
s: seq[TEventHandler]
EInvalidEvent* = object of EInvalidValue
EventEmitter* = object ## An object that fires events and holds event handlers for an object.
s: seq[EventHandler]
EventError* = object of ValueError
{.deprecated: [TEventArgs: EventArgs, TEventHandler: EventHandler,
TEventEmitter: EventEmitter, EInvalidEvent: EventError].}
proc initEventHandler*(name: string): TEventHandler =
## Initializes an EventHandler with the specified name and returns it.

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -25,13 +25,13 @@ else:
import inotify, os, asyncio, tables
type
PFSMonitor* = ref TFSMonitor
TFSMonitor = object of TObject
FSMonitor* = ref FSMonitorObj
FSMonitorObj = object of RootObj
fd: cint
handleEvent: proc (m: PFSMonitor, ev: TMonitorEvent) {.closure.}
handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.}
targets: TTable[cint, string]
TMonitorEventType* = enum ## Monitor event type
MonitorEventType* = enum ## Monitor event type
MonitorAccess, ## File was accessed.
MonitorAttrib, ## Metadata changed.
MonitorCloseWrite, ## Writtable file was closed.
@ -45,8 +45,8 @@ type
MonitorOpen, ## File was opened.
MonitorAll ## Filter for all event types.
TMonitorEvent* = object
case kind*: TMonitorEventType ## Type of the event.
MonitorEvent* = object
case kind*: MonitorEventType ## Type of the event.
of MonitorMoveSelf, MonitorMoved:
oldPath*: string ## Old absolute location
newPath*: string ## New absolute location
@ -58,6 +58,9 @@ type
## watched.
wd*: cint ## Watch descriptor.
{.deprecated: [PFSMonitor: FSMonitor, TFSMonitor: FSMonitorObj,
TMonitorEventType: MonitorEventType, TMonitorEvent: MonitorEvent].}
const
MaxEvents = 100
@ -67,7 +70,7 @@ proc newMonitor*(): PFSMonitor =
result.targets = initTable[cint, string]()
result.fd = inotifyInit()
if result.fd < 0:
OSError(OSLastError())
raiseOSError(osLastError())
proc add*(monitor: PFSMonitor, target: string,
filters = {MonitorAll}): cint {.discardable.} =
@ -101,7 +104,7 @@ proc del*(monitor: PFSMonitor, wd: cint) =
##
## If ``wd`` is not a part of ``monitor`` an EOS error is raised.
if inotifyRmWatch(monitor.fd, wd) < 0:
OSError(OSLastError())
raiseOSError(osLastError())
proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] =
result = @[]
@ -197,18 +200,19 @@ proc register*(d: PDispatcher, monitor: PFSMonitor,
d.register(deleg)
when isMainModule:
var disp = newDispatcher()
var monitor = newMonitor()
echo monitor.add("/home/dom/inotifytests/")
disp.register(monitor,
proc (m: PFSMonitor, ev: TMonitorEvent) =
echo("Got event: ", ev.kind)
if ev.kind == MonitorMoved:
echo("From ", ev.oldPath, " to ", ev.newPath)
echo("Name is ", ev.name)
else:
echo("Name ", ev.name, " fullname ", ev.fullName))
while true:
if not disp.poll(): break
proc main =
var disp = newDispatcher()
var monitor = newMonitor()
echo monitor.add("/home/dom/inotifytests/")
disp.register(monitor,
proc (m: PFSMonitor, ev: TMonitorEvent) =
echo("Got event: ", ev.kind)
if ev.kind == MonitorMoved:
echo("From ", ev.oldPath, " to ", ev.newPath)
echo("Name is ", ev.name)
else:
echo("Name ", ev.name, " fullname ", ev.fullName))
while true:
if not disp.poll(): break
main()

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Dominik Picheta
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -14,8 +14,8 @@ import sockets, strutils, parseutils, times, os, asyncio
## by `RFC 959 <http://tools.ietf.org/html/rfc959>`_.
##
## This module provides both a synchronous and asynchronous implementation.
## The asynchronous implementation requires you to use the ``AsyncFTPClient``
## function. You are then required to register the ``PAsyncFTPClient`` with a
## The asynchronous implementation requires you to use the ``asyncFTPClient``
## function. You are then required to register the ``AsyncFTPClient`` with a
## asyncio dispatcher using the ``register`` function. Take a look at the
## asyncio module documentation for more information.
##
@ -24,64 +24,63 @@ import sockets, strutils, parseutils, times, os, asyncio
##
## Here is some example usage of this module:
##
## .. code-block:: Nimrod
## var ftp = FTPClient("example.org", user = "user", pass = "pass")
## .. code-block:: Nim
## var ftp = ftpClient("example.org", user = "user", pass = "pass")
## ftp.connect()
## ftp.retrFile("file.ext", "file.ext")
##
## **Warning:** The API of this module is unstable, and therefore is subject
## to change.
type
TFTPClient* = object of TObject
FTPClientObj* = object of RootObj
case isAsync: bool
of false:
csock: TSocket # Command connection socket
dsock: TSocket # Data connection socket
csock: Socket # Command connection socket
dsock: Socket # Data connection socket
else:
dummyA, dummyB: pointer # workaround a Nimrod API issue
asyncCSock: PAsyncSocket
asyncDSock: PAsyncSocket
handleEvent*: proc (ftp: PAsyncFTPClient, ev: TFTPEvent){.closure,gcsafe.}
disp: PDispatcher
asyncDSockID: PDelegate
asyncCSock: AsyncSocket
asyncDSock: AsyncSocket
handleEvent*: proc (ftp: AsyncFTPClient, ev: FTPEvent){.closure,gcsafe.}
disp: Dispatcher
asyncDSockID: Delegate
user, pass: string
address: string
port: TPort
port: Port
jobInProgress: bool
job: ref TFTPJob
job: ref FTPJob
dsockConnected: bool
PFTPClient* = ref TFTPClient
FTPClient* = ref FTPClientObj
FTPJobType* = enum
JRetrText, JRetr, JStore
TFTPJob = object
FTPJob = object
prc: proc (ftp: PFTPClient, async: bool): bool {.nimcall, gcsafe.}
case typ*: FTPJobType
of JRetrText:
lines: string
of JRetr, JStore:
file: TFile
file: File
filename: string
total: biggestInt # In bytes.
progress: biggestInt # In bytes.
oneSecond: biggestInt # Bytes transferred in one second.
total: BiggestInt # In bytes.
progress: BiggestInt # In bytes.
oneSecond: BiggestInt # Bytes transferred in one second.
lastProgressReport: float # Time
toStore: string # Data left to upload (Only used with async)
else: nil
PAsyncFTPClient* = ref TAsyncFTPClient ## Async alternative to TFTPClient.
TAsyncFTPClient* = object of TFTPClient
AsyncFTPClient* = ref AsyncFTPClientObj ## Async alternative to TFTPClient.
AsyncFTPClientObj* = object of FTPClientObj
FTPEventType* = enum
EvTransferProgress, EvLines, EvRetr, EvStore
TFTPEvent* = object ## Event
FTPEvent* = object ## Event
filename*: string
case typ*: FTPEventType
of EvLines:
@ -89,13 +88,19 @@ type
of EvRetr, EvStore: ## Retr/Store operation finished.
nil
of EvTransferProgress:
bytesTotal*: biggestInt ## Bytes total.
bytesFinished*: biggestInt ## Bytes transferred.
speed*: biggestInt ## Speed in bytes/s
bytesTotal*: BiggestInt ## Bytes total.
bytesFinished*: BiggestInt ## Bytes transferred.
speed*: BiggestInt ## Speed in bytes/s
currentJob*: FTPJobType ## The current job being performed.
EInvalidReply* = object of ESynch
EFTP* = object of ESynch
ReplyError* = object of IOError
FTPError* = object of IOError
{.deprecated: [
TFTPClient: FTPClientObj, TFTPJob: FTPJob, PAsyncFTPClient: AsyncFTPClient,
TAsyncFTPClient: AsyncFTPClientObj, TFTPEvent: FTPEvent,
EInvalidReply: ReplyError, EFTP: FTPError
].}
proc ftpClient*(address: string, port = TPort(21),
user, pass = ""): PFTPClient =

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Dominik Picheta
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -12,6 +12,8 @@
## may be any Nimrod or user defined type. This module supports matching
## of keys in case-sensitive, case-insensitive and style-insensitive modes.
{.deprecated.}
import
os, hashes, strutils

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -8,13 +8,13 @@
#
## This module implements efficient computations of hash values for diverse
## Nimrod types. All the procs are based on these two building blocks: the `!&
## Nim types. All the procs are based on these two building blocks: the `!&
## proc <#!&>`_ used to start or mix a hash value, and the `!$ proc <#!$>`_
## used to *finish* the hash value. If you want to implement hash procs for
## your custom types you will end up writing the following kind of skeleton of
## code:
##
## .. code-block:: nimrod
## .. code-block:: Nim
## proc hash(x: Something): THash =
## ## Computes a THash from `x`.
## var h: THash = 0
@ -29,7 +29,7 @@
## like for example objects made up of ``strings``, you can simply hash
## together the hash value of the individual fields:
##
## .. code-block:: nimrod
## .. code-block:: Nim
## proc hash(x: Something): THash =
## ## Computes a THash from `x`.
## var h: THash = 0

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -18,13 +18,13 @@
##
## Example:
##
## .. code-block:: nimrod
## var nim = "Nimrod"
## echo h1(a(href="http://nimrod-lang.org", nim))
## .. code-block:: Nim
## var nim = "Nim"
## echo h1(a(href="http://nim-lang.org", nim))
##
## Writes the string::
##
## <h1><a href="http://nimrod-lang.org">Nimrod</a></h1>
## <h1><a href="http://nim-lang.org">Nim</a></h1>
##
import
@ -53,8 +53,7 @@ proc delete[T](s: var seq[T], attr: T): bool =
setLen(s, L-1)
result = true
proc xmlCheckedTag*(e: PNimrodNode, tag: string,
optAttr = "", reqAttr = "",
proc xmlCheckedTag*(e: PNimrodNode, tag: string, optAttr = "", reqAttr = "",
isLeaf = false): PNimrodNode {.compileTime.} =
## use this procedure to define a new XML tag
@ -484,7 +483,7 @@ macro `var`*(e: expr): expr {.immediate.} =
result = xmlCheckedTag(e, "var", commonAttr)
when isMainModule:
var nim = "Nimrod"
echo h1(a(href="http://nimrod-code.org", nim))
var nim = "Nim"
echo h1(a(href="http://nim-lang.org", nim))
echo form(action="test", `accept-charset` = "Content-Type")

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -13,7 +13,7 @@
## It can be used to parse a wild HTML document and output it as valid XHTML
## document (well, if you are lucky):
##
## .. code-block:: nimrod
## .. code-block:: Nim
##
## echo loadHtml("mydirty.html")
##
@ -29,7 +29,7 @@
## and write back the modified version. In this case we look for hyperlinks
## ending with the extension ``.rst`` and convert them to ``.html``.
##
## .. code-block:: nimrod
## .. code-block:: Nim
##
## import htmlparser
## import xmltree # To use '$' for PXmlNode

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2010 Dominik Picheta, Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -21,7 +21,7 @@
## This example uses HTTP GET to retrieve
## ``http://google.com``
##
## .. code-block:: nimrod
## .. code-block:: Nim
## echo(getContent("http://google.com"))
##
## Using HTTP POST
@ -31,7 +31,7 @@
## uses ``multipart/form-data`` as the ``Content-Type`` to send the HTML to
## the server.
##
## .. code-block:: nimrod
## .. code-block:: Nim
## var headers: string = "Content-Type: multipart/form-data; boundary=xyz\c\L"
## var body: string = "--xyz\c\L"
## # soap 1.2 output
@ -54,7 +54,7 @@
## on many operating systems. httpclient will use SSL automatically if you give
## any of the functions a url with the ``https`` schema, for example:
## ``https://github.com/``, you also have to compile with ``ssl`` defined like so:
## ``nimrod c -d:ssl ...``.
## ``nim c -d:ssl ...``.
##
## Timeouts
## ========
@ -80,34 +80,38 @@ import asyncnet, asyncdispatch
import rawsockets
type
TResponse* = tuple[
Response* = tuple[
version: string,
status: string,
headers: PStringTable,
headers: StringTableRef,
body: string]
PProxy* = ref object
Proxy* = ref object
url*: TUrl
auth*: string
EInvalidProtocol* = object of ESynch ## exception that is raised when server
ProtocolError* = object of IOError ## exception that is raised when server
## does not conform to the implemented
## protocol
EHttpRequestErr* = object of ESynch ## Thrown in the ``getContent`` proc
## and ``postContent`` proc,
## when the server returns an error
HttpRequestError* = object of IOError ## Thrown in the ``getContent`` proc
## and ``postContent`` proc,
## when the server returns an error
const defUserAgent* = "Nimrod httpclient/0.1"
{.deprecated: [TResponse: Response, PProxy: Proxy,
EInvalidProtocol: ProtocolError, EHttpRequestErr: HttpRequestError
].}
const defUserAgent* = "Nim httpclient/0.1"
proc httpError(msg: string) =
var e: ref EInvalidProtocol
var e: ref ProtocolError
new(e)
e.msg = msg
raise e
proc fileError(msg: string) =
var e: ref EIO
var e: ref IOError
new(e)
e.msg = msg
raise e
@ -232,7 +236,7 @@ proc parseResponse(s: TSocket, getBody: bool, timeout: int): TResponse =
result.body = ""
type
THttpMethod* = enum ## the requested HttpMethod
HttpMethod* = enum ## the requested HttpMethod
httpHEAD, ## Asks for the response identical to the one that would
## correspond to a GET request, but without the response
## body.
@ -250,6 +254,8 @@ type
httpCONNECT ## Converts the request connection to a transparent
## TCP/IP tunnel, usually used for proxies.
{.deprecated: [THttpMethod: HttpMethod].}
when not defined(ssl):
type PSSLContext = ref object
let defaultSSLContext: PSSLContext = nil
@ -288,7 +294,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
add(headers, "\c\L")
var s = socket()
if s == InvalidSocket: osError(osLastError())
if s == InvalidSocket: raiseOSError(osLastError())
var port = sockets.TPort(80)
if r.scheme == "https":
when defined(ssl):
@ -431,16 +437,18 @@ proc generateHeaders(r: TURL, httpMethod: THttpMethod,
add(result, "\c\L")
type
PAsyncHttpClient* = ref object
socket: PAsyncSocket
AsyncHttpClient* = ref object
socket: AsyncSocket
connected: bool
currentURL: TURL ## Where we are currently connected.
headers: PStringTable
headers: StringTableRef
maxRedirects: int
userAgent: string
{.deprecated: [PAsyncHttpClient: AsyncHttpClient].}
proc newAsyncHttpClient*(userAgent = defUserAgent,
maxRedirects = 5): PAsyncHttpClient =
maxRedirects = 5): AsyncHttpClient =
## Creates a new PAsyncHttpClient instance.
##
## ``userAgent`` specifies the user agent that will be used when making
@ -453,7 +461,7 @@ proc newAsyncHttpClient*(userAgent = defUserAgent,
result.userAgent = defUserAgent
result.maxRedirects = maxRedirects
proc close*(client: PAsyncHttpClient) =
proc close*(client: AsyncHttpClient) =
## Closes any connections held by the HTTP client.
if client.connected:
client.socket.close()

View file

@ -145,7 +145,7 @@ when false:
var buf = alloc(contentLength)
if recv(client, buf, contentLength) != contentLength:
dealloc(buf)
OSError()
raiseOSError()
var inp = process.inputStream
inp.writeData(buf, contentLength)
dealloc(buf)

View file

@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf, Dominik Picheta
# Nim's Runtime Library
# (c) Copyright 2014 Andreas Rumpf, Dominik Picheta
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -35,7 +35,7 @@ import
hashes, strutils, lexbase, streams, unicode
type
TJsonEventKind* = enum ## enumeration of all events that may occur when parsing
JsonEventKind* = enum ## enumeration of all events that may occur when parsing
jsonError, ## an error ocurred during parsing
jsonEof, ## end of file reached
jsonString, ## a string literal
@ -65,7 +65,7 @@ type
tkColon,
tkComma
TJsonError* = enum ## enumeration that lists all errors that can occur
JsonError* = enum ## enumeration that lists all errors that can occur
errNone, ## no error
errInvalidToken, ## invalid token
errStringExpected, ## string expected
@ -78,20 +78,23 @@ type
errEofExpected, ## EOF expected
errExprExpected ## expr expected
TParserState = enum
ParserState = enum
stateEof, stateStart, stateObject, stateArray, stateExpectArrayComma,
stateExpectObjectComma, stateExpectColon, stateExpectValue
TJsonParser* = object of TBaseLexer ## the parser object.
JsonParser* = object of TBaseLexer ## the parser object.
a: string
tok: TTokKind
kind: TJsonEventKind
err: TJsonError
state: seq[TParserState]
kind: JsonEventKind
err: JsonError
state: seq[ParserState]
filename: string
{.deprecated: [TJsonEventKind: JsonEventKind, TJsonError: JsonError,
TJsonParser: JsonParser].}
const
errorMessages: array [TJsonError, string] = [
errorMessages: array [JsonError, string] = [
"no error",
"invalid token",
"string expected",
@ -116,7 +119,7 @@ const
"{", "}", "[", "]", ":", ","
]
proc open*(my: var TJsonParser, input: PStream, filename: string) =
proc open*(my: var JsonParser, input: PStream, filename: string) =
## initializes the parser with an input stream. `Filename` is only used
## for nice error messages.
lexbase.open(my, input)
@ -125,49 +128,49 @@ proc open*(my: var TJsonParser, input: PStream, filename: string) =
my.kind = jsonError
my.a = ""
proc close*(my: var TJsonParser) {.inline.} =
proc close*(my: var JsonParser) {.inline.} =
## closes the parser `my` and its associated input stream.
lexbase.close(my)
proc str*(my: TJsonParser): string {.inline.} =
proc str*(my: JsonParser): string {.inline.} =
## returns the character data for the events: ``jsonInt``, ``jsonFloat``,
## ``jsonString``
assert(my.kind in {jsonInt, jsonFloat, jsonString})
return my.a
proc getInt*(my: TJsonParser): BiggestInt {.inline.} =
proc getInt*(my: JsonParser): BiggestInt {.inline.} =
## returns the number for the event: ``jsonInt``
assert(my.kind == jsonInt)
return parseBiggestInt(my.a)
proc getFloat*(my: TJsonParser): float {.inline.} =
proc getFloat*(my: JsonParser): float {.inline.} =
## returns the number for the event: ``jsonFloat``
assert(my.kind == jsonFloat)
return parseFloat(my.a)
proc kind*(my: TJsonParser): TJsonEventKind {.inline.} =
proc kind*(my: JsonParser): JsonEventKind {.inline.} =
## returns the current event type for the JSON parser
return my.kind
proc getColumn*(my: TJsonParser): int {.inline.} =
proc getColumn*(my: JsonParser): int {.inline.} =
## get the current column the parser has arrived at.
result = getColNumber(my, my.bufpos)
proc getLine*(my: TJsonParser): int {.inline.} =
proc getLine*(my: JsonParser): int {.inline.} =
## get the current line the parser has arrived at.
result = my.lineNumber
proc getFilename*(my: TJsonParser): string {.inline.} =
proc getFilename*(my: JsonParser): string {.inline.} =
## get the filename of the file that the parser processes.
result = my.filename
proc errorMsg*(my: TJsonParser): string =
proc errorMsg*(my: JsonParser): string =
## returns a helpful error message for the event ``jsonError``
assert(my.kind == jsonError)
result = "$1($2, $3) Error: $4" % [
my.filename, $getLine(my), $getColumn(my), errorMessages[my.err]]
proc errorMsgExpected*(my: TJsonParser, e: string): string =
proc errorMsgExpected*(my: JsonParser, e: string): string =
## returns an error message "`e` expected" in the same format as the
## other error messages
result = "$1($2, $3) Error: $4" % [
@ -181,7 +184,7 @@ proc handleHexChar(c: char, x: var int): bool =
of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
else: result = false # error
proc parseString(my: var TJsonParser): TTokKind =
proc parseString(my: var JsonParser): TTokKind =
result = tkString
var pos = my.bufpos + 1
var buf = my.buf
@ -239,7 +242,7 @@ proc parseString(my: var TJsonParser): TTokKind =
inc(pos)
my.bufpos = pos # store back
proc skip(my: var TJsonParser) =
proc skip(my: var JsonParser) =
var pos = my.bufpos
var buf = my.buf
while true:
@ -297,7 +300,7 @@ proc skip(my: var TJsonParser) =
break
my.bufpos = pos
proc parseNumber(my: var TJsonParser) =
proc parseNumber(my: var JsonParser) =
var pos = my.bufpos
var buf = my.buf
if buf[pos] == '-':
@ -328,7 +331,7 @@ proc parseNumber(my: var TJsonParser) =
inc(pos)
my.bufpos = pos
proc parseName(my: var TJsonParser) =
proc parseName(my: var JsonParser) =
var pos = my.bufpos
var buf = my.buf
if buf[pos] in IdentStartChars:
@ -337,7 +340,7 @@ proc parseName(my: var TJsonParser) =
inc(pos)
my.bufpos = pos
proc getTok(my: var TJsonParser): TTokKind =
proc getTok(my: var JsonParser): TTokKind =
setLen(my.a, 0)
skip(my) # skip whitespace, comments
case my.buf[my.bufpos]
@ -381,7 +384,7 @@ proc getTok(my: var TJsonParser): TTokKind =
result = tkError
my.tok = result
proc next*(my: var TJsonParser) =
proc next*(my: var JsonParser) =
## retrieves the first/next event. This controls the parser.
var tk = getTok(my)
var i = my.state.len-1
@ -529,7 +532,10 @@ type
of JArray:
elems*: seq[PJsonNode]
EJsonParsingError* = object of ValueError ## is raised for a JSON error
JsonParsingError* = object of ValueError ## is raised for a JSON error
{.deprecated: [EJsonParsingError: JsonParsingError, TJsonNode: JsonNodeObj,
PJsonNode: JsonNode, TJsonNodeKind: JsonNodeKind].}
proc raiseParseErr*(p: TJsonParser, msg: string) {.noinline, noreturn.} =
## raises an `EJsonParsingError` exception.

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2009 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -36,6 +36,8 @@ type
lineStart: int # index of last line start in buffer
fileOpened: bool
{.deprecated: [TBaseLexer: BaseLexer].}
proc open*(L: var TBaseLexer, input: PStream, bufLen: int = 8192)
## inits the TBaseLexer with a stream to read from

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Andreas Rumpf, Dominik Picheta
#
# See the file "copying.txt", included in this
@ -26,7 +26,7 @@
## The following example demonstrates logging to three different handlers
## simultaneously:
##
## .. code-block:: nimrod
## .. code-block:: nim
##
## var L = newConsoleLogger()
## var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
@ -42,7 +42,7 @@
import strutils, os, times
type
TLevel* = enum ## logging level
Level* = enum ## logging level
lvlAll, ## all levels active
lvlDebug, ## debug level (and any above) active
lvlInfo, ## info level (and any above) active
@ -52,7 +52,7 @@ type
lvlNone ## no levels active
const
LevelNames*: array [TLevel, string] = [
LevelNames*: array [Level, string] = [
"DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "NONE"
]
@ -60,26 +60,29 @@ const
verboseFmtStr* = "$date $time "
type
PLogger* = ref object of PObject ## abstract logger; the base type of all loggers
levelThreshold*: TLevel ## only messages of level >= levelThreshold
Logger* = ref object of RootObj ## abstract logger; the base type of all loggers
levelThreshold*: Leve l ## only messages of level >= levelThreshold
## should be processed
fmtStr: string ## = defaultFmtStr by default, see substituteLog for $date etc.
PConsoleLogger* = ref object of PLogger ## logger that writes the messages to the
## console
ConsoleLogger* = ref object of Logger ## logger that writes the messages to the
## console
PFileLogger* = ref object of PLogger ## logger that writes the messages to a file
FileLogger* = ref object of Logger ## logger that writes the messages to a file
f: TFile
PRollingFileLogger* = ref object of PFileLogger ## logger that writes the
## messages to a file and
## performs log rotation
RollingFileLogger* = ref object of FileLogger ## logger that writes the
## messages to a file and
## performs log rotation
maxLines: int # maximum number of lines
curLine : int
baseName: string # initial filename
baseMode: TFileMode # initial file mode
baseMode: FileMode # initial file mode
logFiles: int # how many log files already created, e.g. basename.1, basename.2...
{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
proc substituteLog(frmt: string): string =
## converts $date to the current date
## converts $time to the current time
@ -105,7 +108,7 @@ proc substituteLog(frmt: string): string =
of "appdir": result.add(app.splitFile.dir)
of "appname": result.add(app.splitFile.name)
method log*(logger: PLogger, level: TLevel,
method log*(logger: Logger, level: Level,
frmt: string, args: varargs[string, `$`]) {.raises: [EBase], tags: [FTime, FWriteIO, FReadIO].} =
## Override this method in custom loggers. Default implementation does
## nothing.

View file

@ -1,20 +1,20 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2013 Andreas Rumpf
# Nim's Runtime Library
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module contains procs for serialization and deseralization of
## arbitrary Nimrod data structures. The serialization format uses JSON.
## arbitrary Nim data structures. The serialization format uses JSON.
##
## **Restriction**: For objects their type is **not** serialized. This means
## essentially that it does not work if the object has some other runtime
## type than its compiletime type:
##
## .. code-block:: nimrod
## .. code-block:: nim
##
## type
## TA = object
@ -211,7 +211,7 @@ proc loadAny(p: var TJsonParser, a: TAny, t: var TTable[biggestInt, pointer]) =
raiseParseErr(p, "float expected")
of akRange: loadAny(p, a.skipRange, t)
proc loadAny(s: PStream, a: TAny, t: var TTable[biggestInt, pointer]) =
proc loadAny(s: PStream, a: TAny, t: var TTable[BiggestInt, pointer]) =
var p: TJsonParser
open(p, s, "unknown file")
next(p)

View file

@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
# Nim's Runtime Library
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -44,7 +44,7 @@ proc validEmailAddress*(s: string): bool {.noSideEffect,
"aero", "jobs", "museum": return true
return false
proc parseInt*(s: string, value: var int, validRange: TSlice[int]) {.
proc parseInt*(s: string, value: var int, validRange: Slice[int]) {.
noSideEffect, rtl, extern: "nmatchParseInt".} =
## parses `s` into an integer in the range `validRange`. If successful,
## `value` is modified to contain the result. Otherwise no exception is
@ -53,7 +53,7 @@ proc parseInt*(s: string, value: var int, validRange: TSlice[int]) {.
var x = value
try:
discard parseutils.parseInt(s, x, 0)
except EOverflow:
except OverflowError:
discard
if x in validRange: value = x

View file

@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
# Nim's Runtime Library
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -9,7 +9,7 @@
## Constructive mathematics is naturally typed. -- Simon Thompson
##
## Basic math routines for Nimrod.
## Basic math routines for Nim.
## This module is available for the `JavaScript target
## <backends.html#the-javascript-target>`_.
@ -41,8 +41,8 @@ const
## for Nimrod's ``float`` type.
type
TFloatClass* = enum ## describes the class a floating point value belongs to.
## This is the type that is returned by `classify`.
FloatClass* = enum ## describes the class a floating point value belongs to.
## This is the type that is returned by `classify`.
fcNormal, ## value is an ordinary nonzero floating point value
fcSubnormal, ## value is a subnormal (a very small) floating point value
fcZero, ## value is zero
@ -51,10 +51,10 @@ type
fcInf, ## value is positive infinity
fcNegInf ## value is negative infinity
proc classify*(x: float): TFloatClass =
proc classify*(x: float): FloatClass =
## classifies a floating point value. Returns `x`'s class as specified by
## `TFloatClass`.
## `FloatClass`.
# JavaScript and most C compilers have no classify:
if x == 0.0:
if 1.0/x == Inf:
@ -287,12 +287,14 @@ proc random[T](a: openArray[T]): T =
result = a[random(a.low..a.len)]
type
TRunningStat* {.pure,final.} = object ## an accumulator for statistical data
n*: int ## number of pushed data
sum*, min*, max*, mean*: float ## self-explaining
RunningStat* = object ## an accumulator for statistical data
n*: int ## number of pushed data
sum*, min*, max*, mean*: float ## self-explaining
oldM, oldS, newS: float
proc push*(s: var TRunningStat, x: float) =
{.deprecated: [TFloatClass: FloatClass, TRunningStat: RunningStat].}
proc push*(s: var RunningStat, x: float) =
## pushes a value `x` for processing
inc(s.n)
# See Knuth TAOCP vol 2, 3rd edition, page 232
@ -313,16 +315,16 @@ proc push*(s: var TRunningStat, x: float) =
s.oldS = s.newS
s.sum = s.sum + x
proc push*(s: var TRunningStat, x: int) =
proc push*(s: var RunningStat, x: int) =
## pushes a value `x` for processing. `x` is simply converted to ``float``
## and the other push operation is called.
push(s, toFloat(x))
proc variance*(s: TRunningStat): float =
proc variance*(s: RunningStat): float =
## computes the current variance of `s`
if s.n > 1: result = s.newS / (toFloat(s.n - 1))
proc standardDeviation*(s: TRunningStat): float =
proc standardDeviation*(s: RunningStat): float =
## computes the current standard deviation of `s`
result = sqrt(variance(s))

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Nimrod Contributors
#
# See the file "copying.txt", included in this
@ -22,7 +22,7 @@ else:
import os
type
TMemFile* = object {.pure.} ## represents a memory mapped file
MemFile* = object ## represents a memory mapped file
mem*: pointer ## a pointer to the memory mapped file. The pointer
## can be used directly to change the contents of the
## file, if it was opened with write access.
@ -34,8 +34,9 @@ type
else:
handle: cint
{.deprecated: [TMemFile: MemFile].}
proc mapMem*(m: var TMemFile, mode: FileMode = fmRead,
proc mapMem*(m: var MemFile, mode: FileMode = fmRead,
mappedSize = -1, offset = 0): pointer =
var readonly = mode == fmRead
when defined(windows):
@ -60,27 +61,27 @@ proc mapMem*(m: var TMemFile, mode: FileMode = fmRead,
osError(osLastError())
proc unmapMem*(f: var TMemFile, p: pointer, size: int) =
proc unmapMem*(f: var MemFile, p: pointer, size: int) =
## unmaps the memory region ``(p, <p+size)`` of the mapped file `f`.
## All changes are written back to the file system, if `f` was opened
## with write access. ``size`` must be of exactly the size that was requested
## via ``mapMem``.
when defined(windows):
if unmapViewOfFile(p) == 0: osError(osLastError())
if unmapViewOfFile(p) == 0: raiseOSError(osLastError())
else:
if munmap(p, size) != 0: osError(osLastError())
if munmap(p, size) != 0: raiseOSError(osLastError())
proc open*(filename: string, mode: FileMode = fmRead,
mappedSize = -1, offset = 0, newFileSize = -1): TMemFile =
mappedSize = -1, offset = 0, newFileSize = -1): MemFile =
## opens a memory mapped file. If this fails, ``EOS`` is raised.
## `newFileSize` can only be set if the file does not exist and is opened
## with write access (e.g., with fmReadWrite). `mappedSize` and `offset`
## can be used to map only a slice of the file. Example:
##
## .. code-block:: nimrod
## .. code-block:: nim
## var
## mm, mm_full, mm_half: TMemFile
## mm, mm_full, mm_half: MemFile
##
## mm = memfiles.open("/tmp/test.mmap", mode = fmWrite, newFileSize = 1024) # Create a new file
## mm.close()
@ -100,11 +101,11 @@ proc open*(filename: string, mode: FileMode = fmRead,
result.size = 0
when defined(windows):
template fail(errCode: TOSErrorCode, msg: expr) =
template fail(errCode: OSErrorCode, msg: expr) =
rollback()
if result.fHandle != 0: discard closeHandle(result.fHandle)
if result.mapHandle != 0: discard closeHandle(result.mapHandle)
osError(errCode)
raiseOSError(errCode)
# return false
#raise newException(EIO, msg)
@ -169,10 +170,10 @@ proc open*(filename: string, mode: FileMode = fmRead,
else: result.size = fileSize.int
else:
template fail(errCode: TOSErrorCode, msg: expr) =
template fail(errCode: OSErrorCode, msg: expr) =
rollback()
if result.handle != 0: discard close(result.handle)
osError(errCode)
raiseOSError(errCode)
var flags = if readonly: O_RDONLY else: O_RDWR
@ -214,12 +215,12 @@ proc open*(filename: string, mode: FileMode = fmRead,
if result.mem == cast[pointer](MAP_FAILED):
fail(osLastError(), "file mapping failed")
proc close*(f: var TMemFile) =
proc close*(f: var MemFile) =
## closes the memory mapped file `f`. All changes are written back to the
## file system, if `f` was opened with write access.
var error = false
var lastErr: TOSErrorCode
var lastErr: OSErrorCode
when defined(windows):
if f.fHandle != INVALID_HANDLE_VALUE:
@ -242,5 +243,5 @@ proc close*(f: var TMemFile) =
else:
f.handle = 0
if error: osError(lastErr)
if error: raiseOSError(lastErr)

View file

@ -1,24 +1,26 @@
import unsigned
type
TMersenneTwister* = object
MersenneTwister* = object
mt: array[0..623, uint32]
index: int
proc newMersenneTwister*(seed: int): TMersenneTwister =
{.deprecated: [TMersenneTwister: MersenneTwister].}
proc newMersenneTwister*(seed: int): MersenneTwister =
result.index = 0
result.mt[0]= uint32(seed)
for i in 1..623'u32:
result.mt[i]= (0x6c078965'u32 * (result.mt[i-1] xor (result.mt[i-1] shr 30'u32)) + i)
proc generateNumbers(m: var TMersenneTwister) =
proc generateNumbers(m: var MersenneTwister) =
for i in 0..623:
var y = (m.mt[i] and 0x80000000'u32) + (m.mt[(i+1) mod 624] and 0x7fffffff'u32)
m.mt[i] = m.mt[(i+397) mod 624] xor uint32(y shr 1'u32)
if (y mod 2'u32) != 0:
m.mt[i] = m.mt[i] xor 0x9908b0df'u32
proc getNum*(m: var TMersenneTwister): int =
proc getNum*(m: var MersenneTwister): int =
if m.index == 0:
generateNumbers(m)
var y = m.mt[m.index]
@ -29,11 +31,9 @@ proc getNum*(m: var TMersenneTwister): int =
m.index = (m.index+1) mod 624
return int(y)
# Test
when isMainModule:
var mt = newMersenneTwister(2525)
for i in 0..99:
echo mt.getNum
echo mt.getNum

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -10,8 +10,10 @@
## This module implements a mimetypes database
import strtabs
type
TMimeDB* = object
mimes: PStringTable
MimeDB* = object
mimes: StringTableRef
{.deprecated: [TMimeDB: MimeDB].}
const mimes* = {
"ez": "application/andrew-inset",
@ -489,20 +491,19 @@ const mimes* = {
"vrml": "x-world/x-vrml",
"wrl": "x-world/x-vrml"}
proc newMimetypes*(): TMimeDB =
proc newMimetypes*(): MimeDB =
## Creates a new Mimetypes database. The database will contain the most
## common mimetypes.
result.mimes = mimes.newStringTable()
proc getMimetype*(mimedb: TMimeDB, ext: string, default = "text/plain"): string =
proc getMimetype*(mimedb: MimeDB, ext: string, default = "text/plain"): string =
## Gets mimetype which corresponds to ``ext``. Returns ``default`` if ``ext``
## could not be found.
result = mimedb.mimes[ext]
if result == "":
return default
proc getExt*(mimedb: TMimeDB, mimetype: string, default = "txt"): string =
proc getExt*(mimedb: MimeDB, mimetype: string, default = "txt"): string =
## Gets extension which corresponds to ``mimetype``. Returns ``default`` if
## ``mimetype`` could not be found. Extensions are returned without the
## leading dot.
@ -511,11 +512,11 @@ proc getExt*(mimedb: TMimeDB, mimetype: string, default = "txt"): string =
if m == mimetype:
result = e
proc register*(mimedb: var TMimeDB, ext: string, mimetype: string) =
proc register*(mimedb: var MimeDB, ext: string, mimetype: string) =
## Adds ``mimetype`` to the ``mimedb``.
mimedb.mimes[ext] = mimetype
when isMainModule:
var m = newMimetypes()
echo m.getMimetype("mp4")
echo m.getExt("text/html")
echo m.getExt("text/html")

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -11,7 +11,7 @@
{.deadCodeElim: on.}
import rawsockets, os, strutils, unsigned, parseutils, times
export TPort, `$`, `==`
export Port, `$`, `==`
const useWinVersion = defined(Windows) or defined(nimdoc)
@ -22,25 +22,25 @@ when defined(ssl):
when defined(ssl):
type
ESSL* = object of ESynch
SSLError* = object of Exception
TSSLCVerifyMode* = enum
SSLCVerifyMode* = enum
CVerifyNone, CVerifyPeer
TSSLProtVersion* = enum
SSLProtVersion* = enum
protSSLv2, protSSLv3, protTLSv1, protSSLv23
PSSLContext* = distinct PSSLCTX
SSLContext* = distinct PSSLCTX
TSSLAcceptResult* = enum
SSLAcceptResult* = enum
AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess
const
BufferSize*: int = 4000 ## size of a buffered socket's buffer
type
TSocketImpl* = object ## socket type
fd*: TSocketHandle
SocketImpl* = object ## socket type
fd*: SocketHandle
case isBuffered*: bool # determines whether this socket is buffered.
of true:
buffer*: array[0..BufferSize, char]
@ -57,34 +57,40 @@ type
sslPeekChar*: char
of false: nil
PSocket* = ref TSocketImpl
Socket* = ref SocketImpl
TSOBool* = enum ## Boolean socket options.
SOBool* = enum ## Boolean socket options.
OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
OptOOBInline, OptReuseAddr
TReadLineResult* = enum ## result for readLineAsync
ReadLineResult* = enum ## result for readLineAsync
ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone
ETimeout* = object of ESynch
TimeoutError* = object of Exception
TSocketFlags* {.pure.} = enum
SocketFlag* {.pure.} = enum
Peek,
SafeDisconn ## Ensures disconnection exceptions (ECONNRESET, EPIPE etc) are not thrown.
proc isDisconnectionError*(flags: set[TSocketFlags],
lastError: TOSErrorCode): bool =
{.deprecated: [TSocketFlags: SocketFlag, ETimeout: TimeoutError,
TReadLineResult: ReadLineResult, TSOBool: SOBool, PSocket: Socket,
TSocketImpl: SocketImpl, ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode,
TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext,
TSSLAcceptResult: SSLAcceptResult].}
proc isDisconnectionError*(flags: set[SocketFlag],
lastError: OSErrorCode): bool =
## Determines whether ``lastError`` is a disconnection error. Only does this
## if flags contains ``SafeDisconn``.
when useWinVersion:
TSocketFlags.SafeDisconn in flags and
SocketFlag.SafeDisconn in flags and
lastError.int32 in {WSAECONNRESET, WSAECONNABORTED, WSAENETRESET,
WSAEDISCON, ERROR_NETNAME_DELETED}
else:
TSocketFlags.SafeDisconn in flags and
SocketFlag.SafeDisconn in flags and
lastError.int32 in {ECONNRESET, EPIPE, ENETRESET}
proc toOSFlags*(socketFlags: set[TSocketFlags]): cint =
proc toOSFlags*(socketFlags: set[SocketFlag]): cint =
## Converts the flags into the underlying OS representation.
for f in socketFlags:
case f

View file

@ -1,13 +1,13 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Profiling support for Nimrod. This is an embedded profiler that requires
## Profiling support for Nim. This is an embedded profiler that requires
## ``--profiler:on``. You only need to import this module to get a profiling
## report at program exit.
@ -64,7 +64,7 @@ when withThreads:
var
profilingLock: TLock
InitLock profilingLock
initLock profilingLock
proc hookAux(st: TStackTrace, costs: int) =
# this is quite performance sensitive!

View file

@ -1,16 +1,17 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2013 Robert Persson
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
type OneVarFunction* = proc (x: float): float
type TOneVarFunction* =proc (x:float):float
{.deprecated: [TOneVarFunction: OneVarFunction].}
proc brent*(xmin,xmax:float ,function:TOneVarFunction, tol:float,maxiter=1000):
proc brent*(xmin,xmax:float, function:OneVarFunction, tol:float,maxiter=1000):
tuple[rootx, rooty: float, success: bool]=
## Searches `function` for a root between `xmin` and `xmax`
## using brents method. If the function value at `xmin`and `xmax` has the

View file

@ -1,13 +1,13 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nimrod OID support. An OID is a global ID that consists of a timestamp,
## Nim OID support. An OID is a global ID that consists of a timestamp,
## a unique counter and a random value. This combination should suffice to
## produce a globally distributed unique ID. This implementation was extracted
## from the Mongodb interface and it thus binary compatible with a Mongo OID.
@ -18,11 +18,13 @@
import times, endians
type
Toid* {.pure, final.} = object ## an OID
Oid* = object ## an OID
time: int32 ##
fuzz: int32 ##
count: int32 ##
{.deprecated: [Toid: Oid].}
proc hexbyte*(hex: char): int =
case hex
of '0'..'9': result = (ord(hex) - ord('0'))
@ -30,7 +32,7 @@ proc hexbyte*(hex: char): int =
of 'A'..'F': result = (ord(hex) - ord('A') + 10)
else: discard
proc parseOid*(str: cstring): TOid =
proc parseOid*(str: cstring): Oid =
## parses an OID.
var bytes = cast[cstring](addr(result.time))
var i = 0
@ -38,7 +40,7 @@ proc parseOid*(str: cstring): TOid =
bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1]))
inc(i)
proc oidToString*(oid: TOid, str: cstring) =
proc oidToString*(oid: Oid, str: cstring) =
const hex = "0123456789abcdef"
# work around a compiler bug:
var str = str
@ -52,7 +54,7 @@ proc oidToString*(oid: TOid, str: cstring) =
inc(i)
str[24] = '\0'
proc `$`*(oid: TOid): string =
proc `$`*(oid: Oid): string =
result = newString(25)
oidToString(oid, result)
@ -60,7 +62,7 @@ var
incr: int
fuzz: int32
proc genOid*(): TOid =
proc genOid*(): Oid =
## generates a new OID.
proc rand(): cint {.importc: "rand", header: "<stdlib.h>", nodecl.}
proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".}
@ -79,12 +81,12 @@ proc genOid*(): TOid =
result.fuzz = fuzz
bigEndian32(addr result.count, addr(i))
proc generatedTime*(oid: TOid): TTime =
proc generatedTime*(oid: Oid): Time =
## returns the generated timestamp of the OID.
var tmp: int32
var dummy = oid.time
bigEndian32(addr(tmp), addr(dummy))
result = TTime(tmp)
result = Time(tmp)
when isMainModule:
let xo = genOID()

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -29,18 +29,23 @@ else:
include "system/ansi_c"
type
FReadEnv* = object of ReadIOEffect ## effect that denotes a read
## from an environment variable
FWriteEnv* = object of WriteIOEffect ## effect that denotes a write
## to an environment variable
ReadEnvEffect* = object of ReadIOEffect ## effect that denotes a read
## from an environment variable
WriteEnvEffect* = object of WriteIOEffect ## effect that denotes a write
## to an environment variable
FReadDir* = object of ReadIOEffect ## effect that denotes a write operation to
## the directory structure
FWriteDir* = object of WriteIOEffect ## effect that denotes a write operation to
## the directory structure
ReadDirEffect* = object of ReadIOEffect ## effect that denotes a write
## operation to the directory structure
WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write operation to
## the directory structure
TOSErrorCode* = distinct int32 ## Specifies an OS Error Code.
OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
{.deprecated: [FReadEnv: ReadEnvEffect, FWriteEnv: WriteEnvEffect,
FReadDir: ReadDirEffect,
FWriteDir: WriteDirEffect,
TOSErrorCode: OSErrorCode
].}
const
doslike = defined(windows) or defined(OS2) or defined(DOS)
# DOS-like filesystem
@ -204,7 +209,8 @@ proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} =
result = $os.strerror(errno)
{.push warning[deprecated]: off.}
proc osError*(msg: string = "") {.noinline, rtl, extern: "nos$1", deprecated.} =
proc raiseOSError*(msg: string = "") {.noinline, rtl, extern: "nos$1",
deprecated.} =
## raises an EOS exception with the given message ``msg``.
## If ``msg == ""``, the operating system's error flag
## (``errno``) is converted to a readable error message. On Windows
@ -219,10 +225,12 @@ proc osError*(msg: string = "") {.noinline, rtl, extern: "nos$1", deprecated.} =
raise newException(OSError, msg)
{.pop.}
proc `==`*(err1, err2: TOSErrorCode): bool {.borrow.}
proc `$`*(err: TOSErrorCode): string {.borrow.}
{.deprecated: [osError: raiseOSError].}
proc osErrorMsg*(errorCode: TOSErrorCode): string =
proc `==`*(err1, err2: OSErrorCode): bool {.borrow.}
proc `$`*(err: OSErrorCode): string {.borrow.}
proc osErrorMsg*(errorCode: OSErrorCode): string =
## Converts an OS error code into a human readable string.
##
## The error code can be retrieved using the ``OSLastError`` proc.
@ -249,10 +257,10 @@ proc osErrorMsg*(errorCode: TOSErrorCode): string =
result = $msgbuf
if msgbuf != nil: localFree(msgbuf)
else:
if errorCode != TOSErrorCode(0'i32):
if errorCode != OSErrorCode(0'i32):
result = $os.strerror(errorCode.int32)
proc osError*(errorCode: TOSErrorCode) =
proc raiseOSError*(errorCode: OSErrorCode) =
## Raises an ``EOS`` exception. The ``errorCode`` will determine the
## message, ``OSErrorMsg`` will be used to get this message.
##
@ -268,7 +276,7 @@ proc osError*(errorCode: TOSErrorCode) =
raise e
{.push stackTrace:off.}
proc osLastError*(): TOSErrorCode =
proc osLastError*(): OSErrorCode =
## Retrieves the last operating system error code.
##
## This procedure is useful in the event when an OS call fails. In that case
@ -285,7 +293,7 @@ proc osLastError*(): TOSErrorCode =
when defined(windows):
result = TOSErrorCode(getLastError())
else:
result = TOSErrorCode(errno)
result = OSErrorCode(errno)
{.pop.}
proc unixToNativePath*(path: string, drive=""): string {.
@ -371,7 +379,7 @@ when defined(windows):
f.cFileName[1].int == dot and f.cFileName[2].int == 0)
proc existsFile*(filename: string): bool {.rtl, extern: "nos$1",
tags: [FReadDir].} =
tags: [ReadDirEffect].} =
## Returns true if the file exists, false otherwise.
when defined(windows):
when useWinUnicode:
@ -384,7 +392,7 @@ proc existsFile*(filename: string): bool {.rtl, extern: "nos$1",
var res: TStat
return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode)
proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [FReadDir].} =
proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect].} =
## Returns true iff the directory `dir` exists. If `dir` is a file, false
## is returned.
when defined(windows):
@ -399,7 +407,7 @@ proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [FReadDir].} =
return stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode)
proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
tags: [FReadDir].} =
tags: [ReadDirEffect].} =
## Returns true iff the symlink `link` exists. Will return true
## regardless of whether the link points to a directory or file.
when defined(windows):
@ -701,7 +709,7 @@ proc extractFilename*(path: string): string {.
result = splitPath(path).tail
proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
tags: [FReadDir].} =
tags: [ReadDirEffect].} =
## Returns the full path of `filename`, raises EOS in case of an error.
when defined(windows):
const bufsize = 3072'i32
@ -800,7 +808,7 @@ when defined(Windows):
)
proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
tags: [FReadDir].} =
tags: [ReadDirEffect].} =
## Returns True if both pathname arguments refer to the same physical
## file or directory. Raises an exception if any of the files does not
## exist or information about it can not be obtained.
@ -883,7 +891,7 @@ type
fpOthersRead ## read access for others
proc getFilePermissions*(filename: string): set[TFilePermission] {.
rtl, extern: "nos$1", tags: [FReadDir].} =
rtl, extern: "nos$1", tags: [ReadDirEffect].} =
## retrieves file permissions for `filename`. `OSError` is raised in case of
## an error. On Windows, only the ``readonly`` flag is checked, every other
## permission is available in any case.
@ -915,7 +923,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {.
result = {fpUserExec..fpOthersRead}
proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
rtl, extern: "nos$1", tags: [FWriteDir].} =
rtl, extern: "nos$1", tags: [WriteDirEffect].} =
## sets the file permissions for `filename`. `OSError` is raised in case of
## an error. On Windows, only the ``readonly`` flag is changed, depending on
## ``fpUserWrite``.
@ -1014,7 +1022,7 @@ when defined(Windows):
template setFileAttributes(file, attrs: expr): expr {.immediate.} =
setFileAttributesA(file, attrs)
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
## Removes the `file`. If this fails, `EOS` is raised. This does not fail
## if the file never existed in the first place.
## On Windows, ignores the read-only attribute.
@ -1076,7 +1084,7 @@ when defined(windows):
while true:
var eend = strEnd(e)
add(environment, $e)
e = cast[WideCString](cast[ByteAddress](eend)+2)
e = cast[WideCString](cast[TAddress](eend)+2)
if eend[1].int == 0: break
discard freeEnvironmentStringsW(env)
else:
@ -1130,7 +1138,7 @@ proc findEnvVar(key: string): int =
if startsWith(environment[i], temp): return i
return -1
proc getEnv*(key: string): TaintedString {.tags: [FReadEnv].} =
proc getEnv*(key: string): TaintedString {.tags: [ReadEnvEffect].} =
## Returns the value of the `environment variable`:idx: named `key`.
##
## If the variable does not exist, "" is returned. To distinguish
@ -1144,13 +1152,13 @@ proc getEnv*(key: string): TaintedString {.tags: [FReadEnv].} =
if env == nil: return TaintedString("")
result = TaintedString($env)
proc existsEnv*(key: string): bool {.tags: [FReadEnv].} =
proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} =
## Checks whether the environment variable named `key` exists.
## Returns true if it exists, false otherwise.
if c_getenv(key) != nil: return true
else: return findEnvVar(key) >= 0
proc putEnv*(key, val: string) {.tags: [FWriteEnv].} =
proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} =
## Sets the value of the `environment variable`:idx: named `key` to `val`.
## If an error occurs, `EInvalidEnvVar` is raised.
@ -1175,7 +1183,7 @@ proc putEnv*(key, val: string) {.tags: [FWriteEnv].} =
else:
if setEnvironmentVariableA(key, val) == 0'i32: osError(osLastError())
iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [FReadEnv].} =
iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} =
## Iterate over all `environments variables`:idx:. In the first component
## of the tuple is the name of the current variable stored, in the second
## its value.
@ -1185,7 +1193,7 @@ iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [FReadEnv].} =
yield (TaintedString(substr(environment[i], 0, p-1)),
TaintedString(substr(environment[i], p+1)))
iterator walkFiles*(pattern: string): string {.tags: [FReadDir].} =
iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
## Iterate over all the files that match the `pattern`. On POSIX this uses
## the `glob`:idx: call.
##
@ -1225,7 +1233,7 @@ type
pcLinkToDir ## path refers to a symbolic link to a directory
iterator walkDir*(dir: string): tuple[kind: TPathComponent, path: string] {.
tags: [FReadDir].} =
tags: [ReadDirEffect].} =
## walks over the directory `dir` and yields for each directory or file in
## `dir`. The component type and full path for each item is returned.
## Walking is not recursive.
@ -1278,7 +1286,7 @@ iterator walkDir*(dir: string): tuple[kind: TPathComponent, path: string] {.
discard closedir(d)
iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {.
tags: [FReadDir].} =
tags: [ReadDirEffect].} =
## walks over the directory `dir` and yields for each file in `dir`. The
## full path for each file is returned.
## **Warning**:
@ -1318,7 +1326,7 @@ proc rawRemoveDir(dir: string) =
if rmdir(dir) != 0'i32 and errno != ENOENT: osError(osLastError())
proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
FWriteDir, FReadDir].} =
WriteDirEffect, ReadDirEffect].} =
## Removes the directory `dir` including all subdirectories and files
## in `dir` (recursively).
##
@ -1345,7 +1353,7 @@ proc rawCreateDir(dir: string) =
if res == 0'i32 and getLastError() != 183'i32:
osError(osLastError())
proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
## Creates the `directory`:idx: `dir`.
##
## The directory may contain several subdirectories that do not exist yet.
@ -1568,7 +1576,7 @@ proc copyDirWithPermissions*(source, dest: string,
proc inclFilePermissions*(filename: string,
permissions: set[TFilePermission]) {.
rtl, extern: "nos$1", tags: [FReadDir, FWriteDir].} =
rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect].} =
## a convenience procedure for:
##
## .. code-block:: nimrod
@ -1577,14 +1585,14 @@ proc inclFilePermissions*(filename: string,
proc exclFilePermissions*(filename: string,
permissions: set[TFilePermission]) {.
rtl, extern: "nos$1", tags: [FReadDir, FWriteDir].} =
rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect].} =
## a convenience procedure for:
##
## .. code-block:: nimrod
## setFilePermissions(filename, getFilePermissions(filename)-permissions)
setFilePermissions(filename, getFilePermissions(filename)-permissions)
proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} =
proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} =
## Returns the home directory of the current user.
##
## This proc is wrapped by the expandTilde proc for the convenience of
@ -1592,12 +1600,12 @@ proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} =
when defined(windows): return string(getEnv("USERPROFILE")) & "\\"
else: return string(getEnv("HOME")) & "/"
proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} =
proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} =
## Returns the config directory of the current user for applications.
when defined(windows): return string(getEnv("APPDATA")) & "\\"
else: return string(getEnv("HOME")) & "/.config/"
proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} =
proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} =
## Returns the temporary directory of the current user for applications to
## save temporary files in.
when defined(windows): return string(getEnv("TEMP")) & "\\"
@ -1605,7 +1613,7 @@ proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} =
when defined(nimdoc):
# Common forward declaration docstring block for parameter retrieval procs.
proc paramCount*(): int {.tags: [FReadIO].} =
proc paramCount*(): int {.tags: [ReadIOEffect].} =
## Returns the number of `command line arguments`:idx: given to the
## application.
##
@ -1625,7 +1633,7 @@ when defined(nimdoc):
## else:
## # Do something else!
proc paramStr*(i: int): TaintedString {.tags: [FReadIO].} =
proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} =
## Returns the `i`-th `command line argument`:idx: given to the application.
##
## `i` should be in the range `1..paramCount()`, the `EInvalidIndex`
@ -1826,7 +1834,7 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
close(f)
else: osError(osLastError())
proc findExe*(exe: string): string {.tags: [FReadDir, FReadEnv].} =
proc findExe*(exe: string): string {.tags: [ReadDirEffect, ReadEnvEffect].} =
## Searches for `exe` in the current working directory and then
## in directories listed in the ``PATH`` environment variable.
## Returns "" if the `exe` cannot be found. On DOS-like platforms, `exe`
@ -1854,7 +1862,6 @@ proc expandTilde*(path: string): string =
## let configFile = expandTilde("~" / "appname.cfg")
## echo configFile
## # --> C:\Users\amber\appname.cfg
if len(path) > 1 and path[0] == '~' and (path[1] == '/' or path[1] == '\\'):
result = getHomeDir() / path[2..len(path)-1]
else:
@ -1961,7 +1968,7 @@ proc getFileInfo*(handle: FileHandle): FileInfo =
rawToFormalFileInfo(rawInfo, result)
proc getFileInfo*(file: File): FileInfo =
result = getFileInfo(file.fileHandle())
result = getFileInfo(file.getFileHandle())
proc getFileInfo*(path: string, followSymlink = true): FileInfo =
## Retrieves file information for the file object pointed to by `path`.

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -24,7 +24,7 @@ when defined(linux):
import linux
type
TProcess = object of RootObj
ProcessObj = object of RootObj
when defined(windows):
fProcessHandle: THandle
inHandle, outHandle, errHandle: FileHandle
@ -35,9 +35,9 @@ type
id: TPid
exitCode: cint
PProcess* = ref TProcess ## represents an operating system process
Process* = ref ProcessObj ## represents an operating system process
TProcessOption* = enum ## options that can be passed `startProcess`
ProcessOption* = enum ## options that can be passed `startProcess`
poEchoCmd, ## echo the command before execution
poUsePath, ## Asks system to search for executable using PATH environment
## variable.
@ -47,6 +47,9 @@ type
poStdErrToStdOut, ## merge stdout and stderr to the stdout stream
poParentStreams ## use the parent's streams
{.deprecated: [TProcess: ProcessObj, PProcess: Process,
TProcessOption: ProcessOption].}
const poUseShell* {.deprecated.} = poUsePath
## Deprecated alias for poUsePath.
@ -125,7 +128,7 @@ proc startProcess*(command: string,
args: openArray[string] = [],
env: PStringTable = nil,
options: set[TProcessOption] = {poStdErrToStdOut}):
PProcess {.rtl, extern: "nosp$1", tags: [ExecIOEffect, FReadEnv].}
PProcess {.rtl, extern: "nosp$1", tags: [ExecIOEffect, ReadEnvEffect].}
## Starts a process. `Command` is the executable file, `workingDir` is the
## process's working directory. If ``workingDir == ""`` the current directory
## is used. `args` are the command line arguments that are passed to the
@ -150,7 +153,7 @@ proc startProcess*(command: string,
proc startCmd*(command: string, options: set[TProcessOption] = {
poStdErrToStdOut, poUsePath}): PProcess {.
tags: [ExecIOEffect, FReadEnv], deprecated.} =
tags: [ExecIOEffect, ReadEnvEffect], deprecated.} =
## Deprecated - use `startProcess` directly.
result = startProcess(command=command, options=options + {poEvalCommand})
@ -233,7 +236,7 @@ proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
proc execProcesses*(cmds: openArray[string],
options = {poStdErrToStdOut, poParentStreams},
n = countProcessors()): int {.rtl, extern: "nosp$1",
tags: [ExecIOEffect, TimeEffect, FReadEnv]} =
tags: [ExecIOEffect, TimeEffect, ReadEnvEffect]} =
## executes the commands `cmds` in parallel. Creates `n` processes
## that execute in parallel. The highest return value of all processes
## is returned.
@ -584,12 +587,12 @@ elif not defined(useNimRtl):
when not defined(useFork):
proc startProcessAuxSpawn(data: TStartProcessData): TPid {.
tags: [ExecIOEffect, FReadEnv], gcsafe.}
tags: [ExecIOEffect, ReadEnvEffect], gcsafe.}
proc startProcessAuxFork(data: TStartProcessData): TPid {.
tags: [ExecIOEffect, FReadEnv], gcsafe.}
tags: [ExecIOEffect, ReadEnvEffect], gcsafe.}
{.push stacktrace: off, profiler: off.}
proc startProcessAfterFork(data: ptr TStartProcessData) {.
tags: [ExecIOEffect, FReadEnv], cdecl, gcsafe.}
tags: [ExecIOEffect, ReadEnvEffect], cdecl, gcsafe.}
{.pop.}
proc startProcess(command: string,

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -20,24 +20,24 @@
## The file ``examples/parsecfgex.nim`` demonstrates how to use the
## configuration file parser:
##
## .. code-block:: nimrod
## .. code-block:: nim
## :file: examples/parsecfgex.nim
import
import
hashes, strutils, lexbase, streams
include "system/inclrtl"
type
TCfgEventKind* = enum ## enumeration of all events that may occur when parsing
type
CfgEventKind* = enum ## enumeration of all events that may occur when parsing
cfgEof, ## end of file reached
cfgSectionStart, ## a ``[section]`` has been parsed
cfgKeyValuePair, ## a ``key=value`` pair has been detected
cfgOption, ## a ``--key=value`` command line option
cfgError ## an error ocurred during parsing
TCfgEvent* = object of TObject ## describes a parsing event
CfgEvent* = object of RootObj ## describes a parsing event
case kind*: TCfgEventKind ## the kind of the event
of cfgEof: nil
of cfgSectionStart:
@ -53,28 +53,30 @@ type
msg*: string ## contains the error message. No exceptions
## are thrown if a parse error occurs.
TTokKind = enum
TokKind = enum
tkInvalid, tkEof,
tkSymbol, tkEquals, tkColon, tkBracketLe, tkBracketRi, tkDashDash
TToken {.final.} = object # a token
kind: TTokKind # the type of the token
Token = object # a token
kind: TokKind # the type of the token
literal: string # the parsed (string) literal
TCfgParser* = object of TBaseLexer ## the parser object.
tok: TToken
CfgParser* = object of BaseLexer ## the parser object.
tok: Token
filename: string
{.deprecated: [TCfgEventKind: CfgEventKind, TCfgEvent: CfgEvent,
TTokKind: TokKind, TToken: Token, TCfgParser: CfgParser].}
# implementation
const
SymChars: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF', '.',
'/', '\\'}
SymChars: CharSet = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF', '.',
'/', '\\'}
proc rawGetTok(c: var TCfgParser, tok: var TToken) {.gcsafe.}
proc rawGetTok(c: var CfgParser, tok: var Token) {.gcsafe.}
proc open*(c: var TCfgParser, input: PStream, filename: string,
lineOffset = 0) {.
rtl, extern: "npc$1".} =
proc open*(c: var CfgParser, input: PStream, filename: string,
lineOffset = 0) {.rtl, extern: "npc$1".} =
## initializes the parser with an input stream. `Filename` is only used
## for nice error messages. `lineOffset` can be used to influence the line
## number information in the generated error messages.
@ -85,23 +87,23 @@ proc open*(c: var TCfgParser, input: PStream, filename: string,
inc(c.lineNumber, lineOffset)
rawGetTok(c, c.tok)
proc close*(c: var TCfgParser) {.rtl, extern: "npc$1".} =
proc close*(c: var CfgParser) {.rtl, extern: "npc$1".} =
## closes the parser `c` and its associated input stream.
lexbase.close(c)
proc getColumn*(c: TCfgParser): int {.rtl, extern: "npc$1".} =
proc getColumn*(c: CfgParser): int {.rtl, extern: "npc$1".} =
## get the current column the parser has arrived at.
result = getColNumber(c, c.bufpos)
proc getLine*(c: TCfgParser): int {.rtl, extern: "npc$1".} =
proc getLine*(c: CfgParser): int {.rtl, extern: "npc$1".} =
## get the current line the parser has arrived at.
result = c.lineNumber
proc getFilename*(c: TCfgParser): string {.rtl, extern: "npc$1".} =
proc getFilename*(c: CfgParser): string {.rtl, extern: "npc$1".} =
## get the filename of the file that the parser processes.
result = c.filename
proc handleHexChar(c: var TCfgParser, xi: var int) =
proc handleHexChar(c: var CfgParser, xi: var int) =
case c.buf[c.bufpos]
of '0'..'9':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
@ -115,12 +117,12 @@ proc handleHexChar(c: var TCfgParser, xi: var int) =
else:
discard
proc handleDecChars(c: var TCfgParser, xi: var int) =
proc handleDecChars(c: var CfgParser, xi: var int) =
while c.buf[c.bufpos] in {'0'..'9'}:
xi = (xi * 10) + (ord(c.buf[c.bufpos]) - ord('0'))
inc(c.bufpos)
proc getEscapedChar(c: var TCfgParser, tok: var TToken) =
proc getEscapedChar(c: var CfgParser, tok: var TToken) =
inc(c.bufpos) # skip '\'
case c.buf[c.bufpos]
of 'n', 'N':
@ -169,13 +171,13 @@ proc getEscapedChar(c: var TCfgParser, tok: var TToken) =
else: tok.kind = tkInvalid
else: tok.kind = tkInvalid
proc handleCRLF(c: var TCfgParser, pos: int): int =
proc handleCRLF(c: var CfgParser, pos: int): int =
case c.buf[pos]
of '\c': result = lexbase.handleCR(c, pos)
of '\L': result = lexbase.handleLF(c, pos)
else: result = pos
proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) =
proc getString(c: var CfgParser, tok: var Token, rawMode: bool) =
var pos = c.bufpos + 1 # skip "
var buf = c.buf # put `buf` in a register
tok.kind = tkSymbol
@ -221,7 +223,7 @@ proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) =
inc(pos)
c.bufpos = pos
proc getSymbol(c: var TCfgParser, tok: var TToken) =
proc getSymbol(c: var CfgParser, tok: var Token) =
var pos = c.bufpos
var buf = c.buf
while true:
@ -231,7 +233,7 @@ proc getSymbol(c: var TCfgParser, tok: var TToken) =
c.bufpos = pos
tok.kind = tkSymbol
proc skip(c: var TCfgParser) =
proc skip(c: var CfgParser) =
var pos = c.bufpos
var buf = c.buf
while true:
@ -247,7 +249,7 @@ proc skip(c: var TCfgParser) =
break # EndOfFile also leaves the loop
c.bufpos = pos
proc rawGetTok(c: var TCfgParser, tok: var TToken) =
proc rawGetTok(c: var CfgParser, tok: var Token) =
tok.kind = tkInvalid
setLen(tok.literal, 0)
skip(c)
@ -286,19 +288,19 @@ proc rawGetTok(c: var TCfgParser, tok: var TToken) =
tok.literal = "[EOF]"
else: getSymbol(c, tok)
proc errorStr*(c: TCfgParser, msg: string): string {.rtl, extern: "npc$1".} =
proc errorStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} =
## returns a properly formated error message containing current line and
## column information.
result = `%`("$1($2, $3) Error: $4",
[c.filename, $getLine(c), $getColumn(c), msg])
proc warningStr*(c: TCfgParser, msg: string): string {.rtl, extern: "npc$1".} =
proc warningStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} =
## returns a properly formated warning message containing current line and
## column information.
result = `%`("$1($2, $3) Warning: $4",
[c.filename, $getLine(c), $getColumn(c), msg])
proc ignoreMsg*(c: TCfgParser, e: TCfgEvent): string {.rtl, extern: "npc$1".} =
proc ignoreMsg*(c: CfgParser, e: CfgEvent): string {.rtl, extern: "npc$1".} =
## returns a properly formated warning message containing that
## an entry is ignored.
case e.kind
@ -309,7 +311,7 @@ proc ignoreMsg*(c: TCfgParser, e: TCfgEvent): string {.rtl, extern: "npc$1".} =
of cfgError: result = e.msg
of cfgEof: result = ""
proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent =
proc getKeyValPair(c: var CfgParser, kind: CfgEventKind): CfgEvent =
if c.tok.kind == tkSymbol:
result.kind = kind
result.key = c.tok.literal
@ -329,7 +331,7 @@ proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent =
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
rawGetTok(c, c.tok)
proc next*(c: var TCfgParser): TCfgEvent {.rtl, extern: "npc$1".} =
proc next*(c: var CfgParser): CfgEvent {.rtl, extern: "npc$1".} =
## retrieves the first/next event. This controls the parser.
case c.tok.kind
of tkEof:

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2009 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -13,16 +13,16 @@
## Example: How to use the parser
## ==============================
##
## .. code-block:: nimrod
## .. code-block:: nim
## import os, parsecsv, streams
## var s = newFileStream(ParamStr(1), fmRead)
## if s == nil: quit("cannot open the file" & ParamStr(1))
## var x: TCsvParser
## open(x, s, ParamStr(1))
## var s = newFileStream(paramStr(1), fmRead)
## if s == nil: quit("cannot open the file" & paramStr(1))
## var x: CsvParser
## open(x, s, paramStr(1))
## while readRow(x):
## Echo "new row: "
## echo "new row: "
## for val in items(x.row):
## Echo "##", val, "##"
## echo "##", val, "##"
## close(x)
##
@ -30,28 +30,30 @@ import
lexbase, streams
type
TCsvRow* = seq[string] ## a row in a CSV file
TCsvParser* = object of TBaseLexer ## the parser object.
row*: TCsvRow ## the current row
CsvRow* = seq[string] ## a row in a CSV file
CsvParser* = object of BaseLexer ## the parser object.
row*: CsvRow ## the current row
filename: string
sep, quote, esc: char
skipWhite: bool
currRow: int
EInvalidCsv* = object of EIO ## exception that is raised if
## a parsing error occurs
CsvError* = object of IOError ## exception that is raised if
## a parsing error occurs
{.deprecated: [TCsvRow: CsvRow, TCsvParser: CsvParser, EInvalidCsv: CsvError].}
proc raiseEInvalidCsv(filename: string, line, col: int,
msg: string) {.noreturn.} =
var e: ref EInvalidCsv
var e: ref CsvError
new(e)
e.msg = filename & "(" & $line & ", " & $col & ") Error: " & msg
raise e
proc error(my: TCsvParser, pos: int, msg: string) =
proc error(my: CsvParser, pos: int, msg: string) =
raiseEInvalidCsv(my.filename, my.LineNumber, getColNumber(my, pos), msg)
proc open*(my: var TCsvParser, input: PStream, filename: string,
proc open*(my: var CsvParser, input: Stream, filename: string,
separator = ',', quote = '"', escape = '\0',
skipInitialSpace = false) =
## initializes the parser with an input stream. `Filename` is only used
@ -75,7 +77,7 @@ proc open*(my: var TCsvParser, input: PStream, filename: string,
my.row = @[]
my.currRow = 0
proc parseField(my: var TCsvParser, a: var string) =
proc parseField(my: var CsvParser, a: var string) =
var pos = my.bufpos
var buf = my.buf
if my.skipWhite:
@ -83,7 +85,7 @@ proc parseField(my: var TCsvParser, a: var string) =
setLen(a, 0) # reuse memory
if buf[pos] == my.quote and my.quote != '\0':
inc(pos)
while true:
while true:
var c = buf[pos]
if c == '\0':
my.bufpos = pos # can continue after exception?
@ -121,11 +123,11 @@ proc parseField(my: var TCsvParser, a: var string) =
inc(pos)
my.bufpos = pos
proc processedRows*(my: var TCsvParser): int =
proc processedRows*(my: var CsvParser): int =
## returns number of the processed rows
return my.currRow
proc readRow*(my: var TCsvParser, columns = 0): bool =
proc readRow*(my: var CsvParser, columns = 0): bool =
## reads the next row; if `columns` > 0, it expects the row to have
## exactly this many columns. Returns false if the end of the file
## has been encountered else true.
@ -160,19 +162,19 @@ proc readRow*(my: var TCsvParser, columns = 0): bool =
$col & " columns")
inc(my.currRow)
proc close*(my: var TCsvParser) {.inline.} =
proc close*(my: var CsvParser) {.inline.} =
## closes the parser `my` and its associated input stream.
lexbase.close(my)
when isMainModule:
import os
var s = newFileStream(ParamStr(1), fmRead)
if s == nil: quit("cannot open the file" & ParamStr(1))
var x: TCsvParser
open(x, s, ParamStr(1))
var s = newFileStream(paramStr(1), fmRead)
if s == nil: quit("cannot open the file" & paramStr(1))
var x: CsvParser
open(x, s, paramStr(1))
while readRow(x):
Echo "new row: "
echo "new row: "
for val in items(x.row):
Echo "##", val, "##"
echo "##", val, "##"
close(x)

View file

@ -1,13 +1,13 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
# Nim's Runtime Library
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module provides the standard Nimrod command line parser.
## This module provides the standard Nim command line parser.
## It supports one convenience iterator over all command line options and some
## lower-level features.
##
@ -22,26 +22,28 @@ import
os, strutils
type
TCmdLineKind* = enum ## the detected command line token
CmdLineKind* = enum ## the detected command line token
cmdEnd, ## end of command line reached
cmdArgument, ## argument detected
cmdLongoption, ## a long option ``--option`` detected
cmdShortOption ## a short option ``-c`` detected
TOptParser* =
OptParser* =
object of RootObj ## this object implements the command line parser
cmd: string
pos: int
inShortState: bool
kind*: TCmdLineKind ## the dected command line token
kind*: CmdLineKind ## the dected command line token
key*, val*: TaintedString ## key and value pair; ``key`` is the option
## or the argument, ``value`` is not "" if
## the option was given a value
{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].}
when declared(os.paramCount):
# we cannot provide this for NimRtl creation on Posix, because we can't
# access the command line arguments then!
proc initOptParser*(cmdline = ""): TOptParser =
proc initOptParser*(cmdline = ""): OptParser =
## inits the option parser. If ``cmdline == ""``, the real command line
## (as provided by the ``OS`` module) is taken.
result.pos = 0
@ -57,7 +59,7 @@ when declared(os.paramCount):
result.val = TaintedString""
proc parseWord(s: string, i: int, w: var string,
delim: TCharSet = {'\x09', ' ', '\0'}): int =
delim: CharSet = {'\x09', ' ', '\0'}): int =
result = i
if s[result] == '\"':
inc(result)
@ -70,7 +72,7 @@ proc parseWord(s: string, i: int, w: var string,
add(w, s[result])
inc(result)
proc handleShortOption(p: var TOptParser) =
proc handleShortOption(p: var OptParser) =
var i = p.pos
p.kind = cmdShortOption
add(p.key.string, p.cmd[i])
@ -87,8 +89,7 @@ proc handleShortOption(p: var TOptParser) =
if p.cmd[i] == '\0': p.inShortState = false
p.pos = i
proc next*(p: var TOptParser) {.
rtl, extern: "npo$1".} =
proc next*(p: var OptParser) {.rtl, extern: "npo$1".} =
## parses the first or next option; ``p.kind`` describes what token has been
## parsed. ``p.key`` and ``p.val`` are set accordingly.
var i = p.pos
@ -122,14 +123,12 @@ proc next*(p: var TOptParser) {.
p.kind = cmdArgument
p.pos = parseWord(p.cmd, i, p.key.string)
proc cmdLineRest*(p: TOptParser): TaintedString {.
rtl, extern: "npo$1".} =
proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} =
## retrieves the rest of the command line that has not been parsed yet.
result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString
when declared(initOptParser):
iterator getopt*(): tuple[kind: TCmdLineKind, key, val: TaintedString] =
iterator getopt*(): tuple[kind: CmdLineKind, key, val: TaintedString] =
## This is an convenience iterator for iterating over the command line.
## This uses the TOptParser object. Example:
##

View file

@ -1,13 +1,13 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
# Nim's Runtime Library
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module provides the standard Nimrod command line parser.
## This module provides the standard Nim command line parser.
## It supports one convenience iterator over all command line options and some
## lower-level features.
##
@ -25,22 +25,24 @@ import
os, strutils
type
TCmdLineKind* = enum ## the detected command line token
CmdLineKind* = enum ## the detected command line token
cmdEnd, ## end of command line reached
cmdArgument, ## argument detected
cmdLongOption, ## a long option ``--option`` detected
cmdShortOption ## a short option ``-c`` detected
TOptParser* =
OptParser* =
object of TObject ## this object implements the command line parser
cmd: seq[string]
pos: int
remainingShortOptions: string
kind*: TCmdLineKind ## the dected command line token
kind*: CmdLineKind ## the dected command line token
key*, val*: TaintedString ## key and value pair; ``key`` is the option
## or the argument, ``value`` is not "" if
## the option was given a value
proc initOptParser*(cmdline: seq[string]): TOptParser {.rtl.} =
{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].}
proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} =
## Initalizes option parses with cmdline. cmdline should not contain
## argument 0 - program name.
## If cmdline == nil default to current command line arguments.
@ -54,7 +56,7 @@ proc initOptParser*(cmdline: seq[string]): TOptParser {.rtl.} =
result.cmd = @cmdline
proc initOptParser*(cmdline: string): TOptParser {.rtl, deprecated.} =
proc initOptParser*(cmdline: string): OptParser {.rtl, deprecated.} =
## Initalizes option parses with cmdline. Splits cmdline in on spaces
## and calls initOptParser(openarray[string])
## Do not use.
@ -64,13 +66,13 @@ proc initOptParser*(cmdline: string): TOptParser {.rtl, deprecated.} =
return initOptParser(cmdline.split)
when not defined(createNimRtl):
proc initOptParser*(): TOptParser =
proc initOptParser*(): OptParser =
## Initializes option parser from current command line arguments.
return initOptParser(commandLineParams())
proc next*(p: var TOptParser) {.rtl, extern: "npo$1".}
proc next*(p: var OptParser) {.rtl, extern: "npo$1".}
proc nextOption(p: var TOptParser, token: string, allowEmpty: bool) =
proc nextOption(p: var OptParser, token: string, allowEmpty: bool) =
for splitchar in [':', '=']:
if splitchar in token:
let pos = token.find(splitchar)
@ -85,7 +87,7 @@ proc nextOption(p: var TOptParser, token: string, allowEmpty: bool) =
p.remainingShortOptions = token[0..token.len-1]
p.next()
proc next(p: var TOptParser) =
proc next(p: var OptParser) =
if p.remainingShortOptions.len != 0:
p.kind = cmdShortOption
p.key = TaintedString(p.remainingShortOptions[0..0])
@ -111,20 +113,22 @@ proc next(p: var TOptParser) =
p.key = token
p.val = ""
proc cmdLineRest*(p: TOptParser): TaintedString {.rtl, extern: "npo$1", deprecated.} =
proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1", deprecated.} =
## Returns part of command line string that has not been parsed yet.
## Do not use - does not correctly handle whitespace.
return p.cmd[p.pos..p.cmd.len-1].join(" ")
type
TGetoptResult* = tuple[kind: TCmdLineKind, key, val: TaintedString]
GetoptResult* = tuple[kind: CmdLineKind, key, val: TaintedString]
{.deprecated: [TGetoptResult: GetoptResult].}
when declared(paramCount):
iterator getopt*(): TGetoptResult =
iterator getopt*(): GetoptResult =
## This is an convenience iterator for iterating over the command line.
## This uses the TOptParser object. Example:
## This uses the OptParser object. Example:
##
## .. code-block:: nimrod
## .. code-block:: nim
## var
## filename = ""
## for kind, key, val in getopt():

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2009 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -10,13 +10,13 @@
## The ``parsesql`` module implements a high performance SQL file
## parser. It parses PostgreSQL syntax and the SQL ANSI standard.
import
import
hashes, strutils, lexbase, streams
# ------------------- scanner -------------------------------------------------
type
TTokKind = enum ## enumeration of all SQL tokens
TokKind = enum ## enumeration of all SQL tokens
tkInvalid, ## invalid token
tkEof, ## end of file reached
tkIdentifier, ## abc
@ -38,33 +38,35 @@ type
tkBracketRi, ## ']'
tkDot ## '.'
TToken {.final.} = object # a token
kind: TTokKind # the type of the token
Token = object # a token
kind: TokKind # the type of the token
literal: string # the parsed (string) literal
TSqlLexer* = object of TBaseLexer ## the parser object.
SqlLexer* = object of BaseLexer ## the parser object.
filename: string
{.deprecated: [TToken: Token, TSqlLexer: SqlLexer].}
const
tokKindToStr: array[TTokKind, string] = [
tokKindToStr: array[TokKind, string] = [
"invalid", "[EOF]", "identifier", "quoted identifier", "string constant",
"escape string constant", "dollar quoted constant", "bit string constant",
"hex string constant", "integer constant", "numeric constant", "operator",
";", ":", ",", "(", ")", "[", "]", "."
]
proc open(L: var TSqlLexer, input: PStream, filename: string) =
proc open(L: var SqlLexer, input: Stream, filename: string) =
lexbase.open(L, input)
L.filename = filename
proc close(L: var TSqlLexer) =
proc close(L: var SqlLexer) =
lexbase.close(L)
proc getColumn(L: TSqlLexer): int =
proc getColumn(L: SqlLexer): int =
## get the current column the parser has arrived at.
result = getColNumber(L, L.bufPos)
proc getLine(L: TSqlLexer): int =
proc getLine(L: SqlLexer): int =
result = L.linenumber
proc handleHexChar(c: var TSqlLexer, xi: var int) =
@ -137,10 +139,10 @@ proc getEscapedChar(c: var TSqlLexer, tok: var TToken) =
else: tok.kind = tkInvalid
else: tok.kind = tkInvalid
proc HandleCRLF(c: var TSqlLexer, pos: int): int =
proc handleCRLF(c: var TSqlLexer, pos: int): int =
case c.buf[pos]
of '\c': result = lexbase.HandleCR(c, pos)
of '\L': result = lexbase.HandleLF(c, pos)
of '\c': result = lexbase.handleCR(c, pos)
of '\L': result = lexbase.handleLF(c, pos)
else: result = pos
proc skip(c: var TSqlLexer) =
@ -163,7 +165,7 @@ proc skip(c: var TSqlLexer) =
case buf[pos]
of '\0': break
of '\c', '\L':
pos = HandleCRLF(c, pos)
pos = handleCRLF(c, pos)
buf = c.buf
of '*':
if buf[pos+1] == '/':
@ -181,13 +183,13 @@ proc skip(c: var TSqlLexer) =
else: inc(pos)
else: break
of '\c', '\L':
pos = HandleCRLF(c, pos)
pos = handleCRLF(c, pos)
buf = c.buf
else:
break # EndOfFile also leaves the loop
c.bufpos = pos
proc getString(c: var TSqlLexer, tok: var TToken, kind: TTokKind) =
proc getString(c: var TSqlLexer, tok: var TToken, kind: TokKind) =
var pos = c.bufPos + 1
var buf = c.buf
tok.kind = kind
@ -465,7 +467,7 @@ proc errorStr(L: TSqlLexer, msg: string): string =
# :: left PostgreSQL-style typecast
# [ ] left array element selection
# - right unary minus
# ^ left exponentiation
# ^ left exponentiation
# * / % left multiplication, division, modulo
# + - left addition, subtraction
# IS IS TRUE, IS FALSE, IS UNKNOWN, IS NULL
@ -483,7 +485,7 @@ proc errorStr(L: TSqlLexer, msg: string): string =
# OR left logical disjunction
type
TSqlNodeKind* = enum ## kind of SQL abstract syntax tree
SqlNodeKind* = enum ## kind of SQL abstract syntax tree
nkNone,
nkIdent,
nkStringLit,
@ -536,79 +538,82 @@ type
nkEnumDef
type
EInvalidSql* = object of EInvalidValue ## Invalid SQL encountered
PSqlNode* = ref TSqlNode ## an SQL abstract syntax tree node
TSqlNode* = object ## an SQL abstract syntax tree node
case kind*: TSqlNodeKind ## kind of syntax tree
SqlParseError* = object of ValueError ## Invalid SQL encountered
SqlNode* = ref SqlNodeObj ## an SQL abstract syntax tree node
SqlNodeObj* = object ## an SQL abstract syntax tree node
case kind*: SqlNodeKind ## kind of syntax tree
of nkIdent, nkStringLit, nkBitStringLit, nkHexStringLit,
nkIntegerLit, nkNumericLit:
strVal*: string ## AST leaf: the identifier, numeric literal
## string literal, etc.
else:
sons*: seq[PSqlNode] ## the node's children
sons*: seq[SqlNode] ## the node's children
TSqlParser* = object of TSqlLexer ## SQL parser object
tok: TToken
SqlParser* = object of SqlLexer ## SQL parser object
tok: Token
proc newNode(k: TSqlNodeKind): PSqlNode =
{.deprecated: [EInvalidSql: SqlParseError, PSqlNode: SqlNode,
TSqlNode: SqlNodeObj, TSqlParser: SqlParser, TSqlNodeKind: SqlNodeKind].}
proc newNode(k: SqlNodeKind): SqlNode =
new(result)
result.kind = k
proc newNode(k: TSqlNodeKind, s: string): PSqlNode =
proc newNode(k: SqlNodeKind, s: string): SqlNode =
new(result)
result.kind = k
result.strVal = s
proc len*(n: PSqlNode): int =
proc len*(n: SqlNode): int =
if isNil(n.sons): result = 0
else: result = n.sons.len
proc add*(father, n: PSqlNode) =
proc add*(father, n: SqlNode) =
if isNil(father.sons): father.sons = @[]
add(father.sons, n)
proc getTok(p: var TSqlParser) =
proc getTok(p: var SqlParser) =
getTok(p, p.tok)
proc sqlError(p: TSqlParser, msg: string) =
var e: ref EInvalidSql
proc sqlError(p: SqlParser, msg: string) =
var e: ref SqlParseError
new(e)
e.msg = errorStr(p, msg)
raise e
proc isKeyw(p: TSqlParser, keyw: string): bool =
proc isKeyw(p: SqlParser, keyw: string): bool =
result = p.tok.kind == tkIdentifier and
cmpIgnoreCase(p.tok.literal, keyw) == 0
proc isOpr(p: TSqlParser, opr: string): bool =
proc isOpr(p: SqlParser, opr: string): bool =
result = p.tok.kind == tkOperator and
cmpIgnoreCase(p.tok.literal, opr) == 0
proc optKeyw(p: var TSqlParser, keyw: string) =
proc optKeyw(p: var SqlParser, keyw: string) =
if p.tok.kind == tkIdentifier and cmpIgnoreCase(p.tok.literal, keyw) == 0:
getTok(p)
proc expectIdent(p: TSqlParser) =
proc expectIdent(p: SqlParser) =
if p.tok.kind != tkIdentifier and p.tok.kind != tkQuotedIdentifier:
sqlError(p, "identifier expected")
proc expect(p: TSqlParser, kind: TTokKind) =
proc expect(p: SqlParser, kind: TokKind) =
if p.tok.kind != kind:
sqlError(p, tokKindToStr[kind] & " expected")
proc eat(p: var TSqlParser, kind: TTokKind) =
proc eat(p: var SqlParser, kind: TokKind) =
if p.tok.kind == kind:
getTok(p)
else:
sqlError(p, tokKindToStr[kind] & " expected")
proc eat(p: var TSqlParser, keyw: string) =
proc eat(p: var SqlParser, keyw: string) =
if isKeyw(p, keyw):
getTok(p)
else:
sqlError(p, keyw.toUpper() & " expected")
proc parseDataType(p: var TSqlParser): PSqlNode =
proc parseDataType(p: var SqlParser): SqlNode =
if isKeyw(p, "enum"):
result = newNode(nkEnumDef)
getTok(p)
@ -636,7 +641,7 @@ proc parseDataType(p: var TSqlParser): PSqlNode =
getTok(p)
eat(p, tkParRi)
proc getPrecedence(p: TSqlParser): int =
proc getPrecedence(p: SqlParser): int =
if isOpr(p, "*") or isOpr(p, "/") or isOpr(p, "%"):
result = 6
elif isOpr(p, "+") or isOpr(p, "-"):
@ -655,9 +660,9 @@ proc getPrecedence(p: TSqlParser): int =
else:
result = - 1
proc parseExpr(p: var TSqlParser): PSqlNode
proc parseExpr(p: var SqlParser): SqlNode
proc identOrLiteral(p: var TSqlParser): PSqlNode =
proc identOrLiteral(p: var SqlParser): SqlNode =
case p.tok.kind
of tkIdentifier, tkQuotedIdentifier:
result = newNode(nkIdent, p.tok.literal)
@ -685,7 +690,7 @@ proc identOrLiteral(p: var TSqlParser): PSqlNode =
sqlError(p, "expression expected")
getTok(p) # we must consume a token here to prevend endless loops!
proc primary(p: var TSqlParser): PSqlNode =
proc primary(p: var SqlParser): SqlNode =
if p.tok.kind == tkOperator or isKeyw(p, "not"):
result = newNode(nkPrefix)
result.add(newNode(nkIdent, p.tok.literal))
@ -723,9 +728,9 @@ proc primary(p: var TSqlParser): PSqlNode =
getTok(p)
else: break
proc lowestExprAux(p: var TSqlParser, v: var PSqlNode, limit: int): int =
proc lowestExprAux(p: var SqlParser, v: var SqlNode, limit: int): int =
var
v2, node, opNode: PSqlNode
v2, node, opNode: SqlNode
v = primary(p) # expand while operators have priorities higher than 'limit'
var opPred = getPrecedence(p)
result = opPred
@ -740,14 +745,14 @@ proc lowestExprAux(p: var TSqlParser, v: var PSqlNode, limit: int): int =
v = node
opPred = getPrecedence(p)
proc parseExpr(p: var TSqlParser): PSqlNode =
proc parseExpr(p: var SqlParser): SqlNode =
discard lowestExprAux(p, result, - 1)
proc parseTableName(p: var TSqlParser): PSqlNode =
proc parseTableName(p: var SqlParser): SqlNode =
expectIdent(p)
result = primary(p)
proc parseColumnReference(p: var TSqlParser): PSqlNode =
proc parseColumnReference(p: var SqlParser): SqlNode =
result = parseTableName(p)
if p.tok.kind == tkParLe:
getTok(p)
@ -760,12 +765,12 @@ proc parseColumnReference(p: var TSqlParser): PSqlNode =
result.add(parseTableName(p))
eat(p, tkParRi)
proc parseCheck(p: var TSqlParser): PSqlNode =
proc parseCheck(p: var SqlParser): SqlNode =
getTok(p)
result = newNode(nkCheck)
result.add(parseExpr(p))
proc parseConstraint(p: var TSqlParser): PSqlNode =
proc parseConstraint(p: var SqlParser): SqlNode =
getTok(p)
result = newNode(nkConstraint)
expectIdent(p)
@ -774,7 +779,7 @@ proc parseConstraint(p: var TSqlParser): PSqlNode =
eat(p, "check")
result.add(parseExpr(p))
proc parseColumnConstraints(p: var TSqlParser, result: PSqlNode) =
proc parseColumnConstraints(p: var SqlParser, result: SqlNode) =
while true:
if isKeyw(p, "default"):
getTok(p)
@ -806,7 +811,7 @@ proc parseColumnConstraints(p: var TSqlParser, result: PSqlNode) =
else:
break
proc parseColumnDef(p: var TSqlParser): PSqlNode =
proc parseColumnDef(p: var SqlParser): SqlNode =
expectIdent(p)
result = newNode(nkColumnDef)
result.add(newNode(nkIdent, p.tok.literal))
@ -814,7 +819,7 @@ proc parseColumnDef(p: var TSqlParser): PSqlNode =
result.add(parseDataType(p))
parseColumnConstraints(p, result)
proc parseIfNotExists(p: var TSqlParser, k: TSqlNodeKind): PSqlNode =
proc parseIfNotExists(p: var SqlParser, k: TSqlNodeKind): SqlNode =
getTok(p)
if isKeyw(p, "if"):
getTok(p)
@ -824,7 +829,7 @@ proc parseIfNotExists(p: var TSqlParser, k: TSqlNodeKind): PSqlNode =
else:
result = newNode(k)
proc parseParIdentList(p: var TSqlParser, father: PSqlNode) =
proc parseParIdentList(p: var SqlParser, father: SqlNode) =
eat(p, tkParLe)
while true:
expectIdent(p)
@ -834,7 +839,7 @@ proc parseParIdentList(p: var TSqlParser, father: PSqlNode) =
getTok(p)
eat(p, tkParRi)
proc parseTableConstraint(p: var TSqlParser): PSqlNode =
proc parseTableConstraint(p: var SqlParser): SqlNode =
if isKeyw(p, "primary"):
getTok(p)
eat(p, "key")
@ -861,7 +866,7 @@ proc parseTableConstraint(p: var TSqlParser): PSqlNode =
else:
sqlError(p, "column definition expected")
proc parseTableDef(p: var TSqlParser): PSqlNode =
proc parseTableDef(p: var SqlParser): SqlNode =
result = parseIfNotExists(p, nkCreateTable)
expectIdent(p)
result.add(newNode(nkIdent, p.tok.literal))
@ -876,7 +881,7 @@ proc parseTableDef(p: var TSqlParser): PSqlNode =
if p.tok.kind != tkComma: break
eat(p, tkParRi)
proc parseTypeDef(p: var TSqlParser): PSqlNode =
proc parseTypeDef(p: var SqlParser): SqlNode =
result = parseIfNotExists(p, nkCreateType)
expectIdent(p)
result.add(newNode(nkIdent, p.tok.literal))
@ -884,12 +889,12 @@ proc parseTypeDef(p: var TSqlParser): PSqlNode =
eat(p, "as")
result.add(parseDataType(p))
proc parseWhere(p: var TSqlParser): PSqlNode =
proc parseWhere(p: var SqlParser): SqlNode =
getTok(p)
result = newNode(nkWhere)
result.add(parseExpr(p))
proc parseIndexDef(p: var TSqlParser): PSqlNode =
proc parseIndexDef(p: var SqlParser): SqlNode =
result = parseIfNotExists(p, nkCreateIndex)
if isKeyw(p, "primary"):
getTok(p)
@ -914,7 +919,7 @@ proc parseIndexDef(p: var TSqlParser): PSqlNode =
getTok(p)
eat(p, tkParRi)
proc parseInsert(p: var TSqlParser): PSqlNode =
proc parseInsert(p: var SqlParser): SqlNode =
getTok(p)
eat(p, "into")
expectIdent(p)
@ -941,7 +946,7 @@ proc parseInsert(p: var TSqlParser): PSqlNode =
result.add(n)
eat(p, tkParRi)
proc parseUpdate(p: var TSqlParser): PSqlNode =
proc parseUpdate(p: var SqlParser): SqlNode =
getTok(p)
result = newNode(nkUpdate)
result.add(primary(p))
@ -962,7 +967,7 @@ proc parseUpdate(p: var TSqlParser): PSqlNode =
else:
result.add(nil)
proc parseDelete(p: var TSqlParser): PSqlNode =
proc parseDelete(p: var SqlParser): SqlNode =
getTok(p)
result = newNode(nkDelete)
eat(p, "from")
@ -972,7 +977,7 @@ proc parseDelete(p: var TSqlParser): PSqlNode =
else:
result.add(nil)
proc parseSelect(p: var TSqlParser): PSqlNode =
proc parseSelect(p: var SqlParser): SqlNode =
getTok(p)
if isKeyw(p, "distinct"):
getTok(p)
@ -1041,7 +1046,7 @@ proc parseSelect(p: var TSqlParser): PSqlNode =
getTok(p)
result.add(n)
proc parseStmt(p: var TSqlParser): PSqlNode =
proc parseStmt(p: var SqlParser): SqlNode =
if isKeyw(p, "create"):
getTok(p)
optKeyw(p, "cached")
@ -1071,7 +1076,7 @@ proc parseStmt(p: var TSqlParser): PSqlNode =
else:
sqlError(p, "CREATE expected")
proc open(p: var TSqlParser, input: PStream, filename: string) =
proc open(p: var SqlParser, input: PStream, filename: string) =
## opens the parser `p` and assigns the input stream `input` to it.
## `filename` is only used for error messages.
open(TSqlLexer(p), input, filename)
@ -1079,7 +1084,7 @@ proc open(p: var TSqlParser, input: PStream, filename: string) =
p.tok.literal = ""
getTok(p)
proc parse(p: var TSqlParser): PSqlNode =
proc parse(p: var SqlParser): SqlNode =
## parses the content of `p`'s input stream and returns the SQL AST.
## Syntax errors raise an `EInvalidSql` exception.
result = newNode(nkStmtList)
@ -1090,24 +1095,24 @@ proc parse(p: var TSqlParser): PSqlNode =
if result.len == 1:
result = result.sons[0]
proc close(p: var TSqlParser) =
proc close(p: var SqlParser) =
## closes the parser `p`. The associated input stream is closed too.
close(TSqlLexer(p))
proc parseSQL*(input: PStream, filename: string): PSqlNode =
proc parseSQL*(input: PStream, filename: string): SqlNode =
## parses the SQL from `input` into an AST and returns the AST.
## `filename` is only used for error messages.
## Syntax errors raise an `EInvalidSql` exception.
var p: TSqlParser
var p: SqlParser
open(p, input, filename)
try:
result = parse(p)
finally:
close(p)
proc ra(n: PSqlNode, s: var string, indent: int)
proc ra(n: SqlNode, s: var string, indent: int)
proc rs(n: PSqlNode, s: var string, indent: int,
proc rs(n: SqlNode, s: var string, indent: int,
prefix = "(", suffix = ")",
sep = ", ") =
if n.len > 0:
@ -1117,7 +1122,7 @@ proc rs(n: PSqlNode, s: var string, indent: int,
ra(n.sons[i], s, indent)
s.add(suffix)
proc ra(n: PSqlNode, s: var string, indent: int) =
proc ra(n: SqlNode, s: var string, indent: int) =
if n == nil: return
case n.kind
of nkNone: discard
@ -1320,7 +1325,7 @@ proc ra(n: PSqlNode, s: var string, indent: int) =
#for x, y, z in db.select(fromm = a, b where = a.name == b.name):
# writeln x, y, z
proc renderSQL*(n: PSqlNode): string =
proc renderSQL*(n: SqlNode): string =
## Converts an SQL abstract syntax tree to its string representation.
result = ""
ra(n, result, 0)

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -15,12 +15,14 @@
import strutils
type
TUrl* = tuple[ ## represents a *Uniform Resource Locator* (URL)
## any optional component is "" if it does not exist
Url* = tuple[ ## represents a *Uniform Resource Locator* (URL)
## any optional component is "" if it does not exist
scheme, username, password,
hostname, port, path, query, anchor: string]
proc parseUrl*(url: string): TUrl {.deprecated.} =
{.deprecated: [TUrl: Url].}
proc parseUrl*(url: string): Url {.deprecated.} =
var i = 0
var scheme, username, password: string = ""
@ -86,7 +88,7 @@ proc parseUrl*(url: string): TUrl {.deprecated.} =
return (scheme, username, password, hostname, port, path, query, anchor)
proc `$`*(u: TUrl): string {.deprecated.} =
proc `$`*(u: Url): string {.deprecated.} =
## turns the URL `u` into its string representation.
result = ""
if u.scheme.len > 0:

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -35,7 +35,7 @@ proc parseHex*(s: string, number: var int, start = 0): int {.
## can use this feature to *chain* calls, though the result int will quickly
## overflow. Example:
##
## .. code-block:: nimrod
## .. code-block:: nim
## var value = 0
## discard parseHex("0x38", value)
## assert value == 56
@ -332,7 +332,7 @@ proc parseFloat*(s: string, number: var float, start = 0): int {.
number = bf
type
TInterpolatedKind* = enum ## describes for `interpolatedFragments`
InterpolatedKind* = enum ## describes for `interpolatedFragments`
## which part of the interpolated string is
## yielded; for example in "str$$$var${expr}"
ikStr, ## ``str`` part of the interpolated string
@ -340,7 +340,9 @@ type
ikVar, ## ``var`` part of the interpolated string
ikExpr ## ``expr`` part of the interpolated string
iterator interpolatedFragments*(s: string): tuple[kind: TInterpolatedKind,
{.deprecated: [TInterpolatedKind: InterpolatedKind].}
iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
value: string] =
## Tokenizes the string `s` into substrings for interpolation purposes.
##
@ -360,7 +362,7 @@ iterator interpolatedFragments*(s: string): tuple[kind: TInterpolatedKind,
## (ikString, " ")
## (ikDollar, "$")
var i = 0
var kind: TInterpolatedKind
var kind: InterpolatedKind
while true:
var j = i
if s[j] == '$':

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -56,7 +56,7 @@ import
# xmlElementCloseEnd, ## ``/>``
type
TXmlEventKind* = enum ## enumation of all events that may occur when parsing
XmlEventKind* = enum ## enumation of all events that may occur when parsing
xmlError, ## an error ocurred during parsing
xmlEof, ## end of file reached
xmlCharData, ## character data
@ -72,7 +72,7 @@ type
xmlEntity, ## &entity;
xmlSpecial ## ``<! ... data ... >``
TXmlError* = enum ## enumeration that lists all errors that can occur
XmlErrorKind* = enum ## enumeration that lists all errors that can occur
errNone, ## no error
errEndOfCDataExpected, ## ``]]>`` expected
errNameExpected, ## name expected
@ -83,23 +83,26 @@ type
errQuoteExpected, ## ``"`` or ``'`` expected
errEndOfCommentExpected ## ``-->`` expected
TParserState = enum
ParserState = enum
stateStart, stateNormal, stateAttr, stateEmptyElementTag, stateError
TXmlParseOption* = enum ## options for the XML parser
XmlParseOption* = enum ## options for the XML parser
reportWhitespace, ## report whitespace
reportComments ## report comments
TXmlParser* = object of TBaseLexer ## the parser object.
XmlParser* = object of TBaseLexer ## the parser object.
a, b, c: string
kind: TXmlEventKind
err: TXmlError
state: TParserState
kind: XmlEventKind
err: XmlErrorKind
state: ParserState
filename: string
options: set[TXmlParseOption]
options: set[XmlParseOption]
{.deprecated: [TXmlParser: XmlParser, TXmlParseOptions: XmlParseOptions,
TXmlError: XmlErrorKind, TXmlEventKind: XmlEventKind].}
const
errorMessages: array [TXmlError, string] = [
errorMessages: array[XmlError, string] = [
"no error",
"']]>' expected",
"name expected",
@ -111,8 +114,8 @@ const
"'-->' expected"
]
proc open*(my: var TXmlParser, input: PStream, filename: string,
options: set[TXmlParseOption] = {}) =
proc open*(my: var XmlParser, input: Stream, filename: string,
options: set[XmlParseOption] = {}) =
## initializes the parser with an input stream. `Filename` is only used
## for nice error messages. The parser's behaviour can be controlled by
## the `options` parameter: If `options` contains ``reportWhitespace``
@ -127,7 +130,7 @@ proc open*(my: var TXmlParser, input: PStream, filename: string,
my.b = ""
my.options = options
proc close*(my: var TXmlParser) {.inline.} =
proc close*(my: var XmlParser) {.inline.} =
## closes the parser `my` and its associated input stream.
lexbase.close(my)

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -32,7 +32,7 @@ const
## can be captured. More subpatterns cannot be captured!
type
TPegKind = enum
PegKind = enum
pkEmpty,
pkAny, ## any character (.)
pkAnyRune, ## any Unicode character (_)
@ -67,16 +67,16 @@ type
pkRule, ## a <- b
pkList, ## a, b
pkStartAnchor ## ^ --> Internal DSL: startAnchor()
TNonTerminalFlag = enum
NonTerminalFlag = enum
ntDeclared, ntUsed
TNonTerminal {.final.} = object ## represents a non terminal symbol
NonTerminalObj = object ## represents a non terminal symbol
name: string ## the name of the symbol
line: int ## line the symbol has been declared/used in
col: int ## column the symbol has been declared/used in
flags: set[TNonTerminalFlag] ## the nonterminal's flags
flags: set[NonTerminalFlag] ## the nonterminal's flags
rule: TNode ## the rule that the symbol refers to
TNode {.final, shallow.} = object
case kind: TPegKind
TNode {.shallow.} = object
case kind: PegKind
of pkEmpty..pkWhitespace: nil
of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string
of pkChar, pkGreedyRepChar: ch: char
@ -84,11 +84,13 @@ type
of pkNonTerminal: nt: PNonTerminal
of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
else: sons: seq[TNode]
PNonTerminal* = ref TNonTerminal
NonTerminal* = ref NonTerminalObj
TPeg* = TNode ## type that represents a PEG
Peg* = TNode ## type that represents a PEG
proc term*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1Str".} =
{.deprecated: [TPeg: Peg].}
proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
## constructs a PEG from a terminal string
if t.len != 1:
result.kind = pkTerminal
@ -97,35 +99,35 @@ proc term*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1Str".} =
result.kind = pkChar
result.ch = t[0]
proc termIgnoreCase*(t: string): TPeg {.
proc termIgnoreCase*(t: string): Peg {.
nosideEffect, rtl, extern: "npegs$1".} =
## constructs a PEG from a terminal string; ignore case for matching
result.kind = pkTerminalIgnoreCase
result.term = t
proc termIgnoreStyle*(t: string): TPeg {.
proc termIgnoreStyle*(t: string): Peg {.
nosideEffect, rtl, extern: "npegs$1".} =
## constructs a PEG from a terminal string; ignore style for matching
result.kind = pkTerminalIgnoreStyle
result.term = t
proc term*(t: char): TPeg {.nosideEffect, rtl, extern: "npegs$1Char".} =
proc term*(t: char): Peg {.nosideEffect, rtl, extern: "npegs$1Char".} =
## constructs a PEG from a terminal char
assert t != '\0'
result.kind = pkChar
result.ch = t
proc charSet*(s: set[char]): TPeg {.nosideEffect, rtl, extern: "npegs$1".} =
proc charSet*(s: set[char]): Peg {.nosideEffect, rtl, extern: "npegs$1".} =
## constructs a PEG from a character set `s`
assert '\0' notin s
result.kind = pkCharChoice
new(result.charChoice)
result.charChoice[] = s
proc len(a: TPeg): int {.inline.} = return a.sons.len
proc add(d: var TPeg, s: TPeg) {.inline.} = add(d.sons, s)
proc len(a: Peg): int {.inline.} = return a.sons.len
proc add(d: var Peg, s: Peg) {.inline.} = add(d.sons, s)
proc addChoice(dest: var TPeg, elem: TPeg) =
proc addChoice(dest: var Peg, elem: Peg) =
var L = dest.len-1
if L >= 0 and dest.sons[L].kind == pkCharChoice:
# caution! Do not introduce false aliasing here!
@ -137,7 +139,7 @@ proc addChoice(dest: var TPeg, elem: TPeg) =
else: add(dest, elem)
else: add(dest, elem)
template multipleOp(k: TPegKind, localOpt: expr) =
template multipleOp(k: PegKind, localOpt: expr) =
result.kind = k
result.sons = @[]
for x in items(a):
@ -149,12 +151,12 @@ template multipleOp(k: TPegKind, localOpt: expr) =
if result.len == 1:
result = result.sons[0]
proc `/`*(a: varargs[TPeg]): TPeg {.
proc `/`*(a: varargs[Peg]): Peg {.
nosideEffect, rtl, extern: "npegsOrderedChoice".} =
## constructs an ordered choice with the PEGs in `a`
multipleOp(pkOrderedChoice, addChoice)
proc addSequence(dest: var TPeg, elem: TPeg) =
proc addSequence(dest: var Peg, elem: Peg) =
var L = dest.len-1
if L >= 0 and dest.sons[L].kind == pkTerminal:
# caution! Do not introduce false aliasing here!
@ -166,12 +168,12 @@ proc addSequence(dest: var TPeg, elem: TPeg) =
else: add(dest, elem)
else: add(dest, elem)
proc sequence*(a: varargs[TPeg]): TPeg {.
proc sequence*(a: varargs[Peg]): Peg {.
nosideEffect, rtl, extern: "npegs$1".} =
## constructs a sequence with all the PEGs from `a`
multipleOp(pkSequence, addSequence)
proc `?`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsOptional".} =
proc `?`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsOptional".} =
## constructs an optional for the PEG `a`
if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar,
pkGreedyRepSet}:
@ -182,7 +184,7 @@ proc `?`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsOptional".} =
result.kind = pkOption
result.sons = @[a]
proc `*`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyRep".} =
proc `*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyRep".} =
## constructs a "greedy repetition" for the PEG `a`
case a.kind
of pkGreedyRep, pkGreedyRepChar, pkGreedyRepSet, pkGreedyAny, pkOption:
@ -200,111 +202,99 @@ proc `*`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyRep".} =
result.kind = pkGreedyRep
result.sons = @[a]
proc `!*`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsSearch".} =
proc `!*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsSearch".} =
## constructs a "search" for the PEG `a`
result.kind = pkSearch
result.sons = @[a]
proc `!*\`*(a: TPeg): TPeg {.noSideEffect, rtl,
proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
extern: "npgegsCapturedSearch".} =
## constructs a "captured search" for the PEG `a`
result.kind = pkCapturedSearch
result.sons = @[a]
when false:
proc contains(a: TPeg, k: TPegKind): bool =
if a.kind == k: return true
case a.kind
of pkEmpty, pkAny, pkAnyRune, pkGreedyAny, pkNewLine, pkTerminal,
pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar, pkGreedyRepChar,
pkCharChoice, pkGreedyRepSet: nil
of pkNonTerminal: return true
else:
for i in 0..a.sons.len-1:
if contains(a.sons[i], k): return true
proc `+`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
proc `+`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
## constructs a "greedy positive repetition" with the PEG `a`
return sequence(a, *a)
proc `&`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
proc `&`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
## constructs an "and predicate" with the PEG `a`
result.kind = pkAndPredicate
result.sons = @[a]
proc `!`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsNotPredicate".} =
proc `!`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsNotPredicate".} =
## constructs a "not predicate" with the PEG `a`
result.kind = pkNotPredicate
result.sons = @[a]
proc any*: TPeg {.inline.} =
proc any*: Peg {.inline.} =
## constructs the PEG `any character`:idx: (``.``)
result.kind = pkAny
proc anyRune*: TPeg {.inline.} =
proc anyRune*: Peg {.inline.} =
## constructs the PEG `any rune`:idx: (``_``)
result.kind = pkAnyRune
proc newLine*: TPeg {.inline.} =
proc newLine*: Peg {.inline.} =
## constructs the PEG `newline`:idx: (``\n``)
result.kind = pkNewline
proc unicodeLetter*: TPeg {.inline.} =
proc unicodeLetter*: Peg {.inline.} =
## constructs the PEG ``\letter`` which matches any Unicode letter.
result.kind = pkLetter
proc unicodeLower*: TPeg {.inline.} =
proc unicodeLower*: Peg {.inline.} =
## constructs the PEG ``\lower`` which matches any Unicode lowercase letter.
result.kind = pkLower
proc unicodeUpper*: TPeg {.inline.} =
proc unicodeUpper*: Peg {.inline.} =
## constructs the PEG ``\upper`` which matches any Unicode uppercase letter.
result.kind = pkUpper
proc unicodeTitle*: TPeg {.inline.} =
proc unicodeTitle*: Peg {.inline.} =
## constructs the PEG ``\title`` which matches any Unicode title letter.
result.kind = pkTitle
proc unicodeWhitespace*: TPeg {.inline.} =
proc unicodeWhitespace*: Peg {.inline.} =
## constructs the PEG ``\white`` which matches any Unicode
## whitespace character.
result.kind = pkWhitespace
proc startAnchor*: TPeg {.inline.} =
proc startAnchor*: Peg {.inline.} =
## constructs the PEG ``^`` which matches the start of the input.
result.kind = pkStartAnchor
proc endAnchor*: TPeg {.inline.} =
proc endAnchor*: Peg {.inline.} =
## constructs the PEG ``$`` which matches the end of the input.
result = !any()
proc capture*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsCapture".} =
proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} =
## constructs a capture with the PEG `a`
result.kind = pkCapture
result.sons = @[a]
proc backref*(index: range[1..MaxSubPatterns]): TPeg {.
proc backref*(index: range[1..MaxSubPatterns]): Peg {.
nosideEffect, rtl, extern: "npegs$1".} =
## constructs a back reference of the given `index`. `index` starts counting
## from 1.
result.kind = pkBackRef
result.index = index-1
proc backrefIgnoreCase*(index: range[1..MaxSubPatterns]): TPeg {.
proc backrefIgnoreCase*(index: range[1..MaxSubPatterns]): Peg {.
nosideEffect, rtl, extern: "npegs$1".} =
## constructs a back reference of the given `index`. `index` starts counting
## from 1. Ignores case for matching.
result.kind = pkBackRefIgnoreCase
result.index = index-1
proc backrefIgnoreStyle*(index: range[1..MaxSubPatterns]): TPeg {.
proc backrefIgnoreStyle*(index: range[1..MaxSubPatterns]): Peg {.
nosideEffect, rtl, extern: "npegs$1".}=
## constructs a back reference of the given `index`. `index` starts counting
## from 1. Ignores style for matching.
result.kind = pkBackRefIgnoreStyle
result.index = index-1
proc spaceCost(n: TPeg): int =
proc spaceCost(n: Peg): int =
case n.kind
of pkEmpty: discard
of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
@ -319,7 +309,7 @@ proc spaceCost(n: TPeg): int =
inc(result, spaceCost(n.sons[i]))
if result >= InlineThreshold: break
proc nonterminal*(n: PNonTerminal): TPeg {.
proc nonterminal*(n: PNonTerminal): Peg {.
nosideEffect, rtl, extern: "npegs$1".} =
## constructs a PEG that consists of the nonterminal symbol
assert n != nil
@ -415,7 +405,7 @@ proc charSetEsc(cc: set[char]): string =
else:
result = '[' & charSetEscAux(cc) & ']'
proc toStrAux(r: TPeg, res: var string) =
proc toStrAux(r: Peg, res: var string) =
case r.kind
of pkEmpty: add(res, "()")
of pkAny: add(res, '.')
@ -501,7 +491,7 @@ proc toStrAux(r: TPeg, res: var string) =
of pkStartAnchor:
add(res, '^')
proc `$` *(r: TPeg): string {.nosideEffect, rtl, extern: "npegsToString".} =
proc `$` *(r: Peg): string {.nosideEffect, rtl, extern: "npegsToString".} =
## converts a PEG to its string representation
result = ""
toStrAux(r, result)
@ -509,12 +499,14 @@ proc `$` *(r: TPeg): string {.nosideEffect, rtl, extern: "npegsToString".} =
# --------------------- core engine -------------------------------------------
type
TCaptures* {.final.} = object ## contains the captured substrings.
Captures* = object ## contains the captured substrings.
matches: array[0..maxSubpatterns-1, tuple[first, last: int]]
ml: int
origStart: int
proc bounds*(c: TCaptures,
{.deprecated: [TCaptures: Captures].}
proc bounds*(c: Captures,
i: range[0..maxSubpatterns-1]): tuple[first, last: int] =
## returns the bounds ``[first..last]`` of the `i`'th capture.
result = c.matches[i]
@ -533,7 +525,7 @@ when not useUnicode:
proc isTitle(a: char): bool {.inline.} = return false
proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'}
proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
nosideEffect, rtl, extern: "npegs$1".} =
## low-level matching proc that implements the PEG interpreter. Use this
## for maximum efficiency (every other PEG operation ends up calling this
@ -734,7 +726,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
of pkBackRef..pkBackRefIgnoreStyle:
if p.index >= c.ml: return -1
var (a, b) = c.matches[p.index]
var n: TPeg
var n: Peg
n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef))
n.term = s.substr(a, b)
result = rawMatch(s, n, start, c)
@ -747,51 +739,51 @@ template fillMatches(s, caps, c: expr) =
for k in 0..c.ml-1:
caps[k] = substr(s, c.matches[k][0], c.matches[k][1])
proc match*(s: string, pattern: TPeg, matches: var openArray[string],
proc match*(s: string, pattern: Peg, matches: var openArray[string],
start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
## the captured substrings in the array ``matches``. If it does not
## match, nothing is written into ``matches`` and ``false`` is
## returned.
var c: TCaptures
var c: Captures
c.origStart = start
result = rawMatch(s, pattern, start, c) == len(s) - start
if result: fillMatches(s, matches, c)
proc match*(s: string, pattern: TPeg,
proc match*(s: string, pattern: Peg,
start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
var c: TCaptures
var c: Captures
c.origStart = start
result = rawMatch(s, pattern, start, c) == len(s)-start
proc matchLen*(s: string, pattern: TPeg, matches: var openArray[string],
proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
## the same as ``match``, but it returns the length of the match,
## if there is no match, -1 is returned. Note that a match length
## of zero can happen. It's possible that a suffix of `s` remains
## that does not belong to the match.
var c: TCaptures
var c: Captures
c.origStart = start
result = rawMatch(s, pattern, start, c)
if result >= 0: fillMatches(s, matches, c)
proc matchLen*(s: string, pattern: TPeg,
proc matchLen*(s: string, pattern: Peg,
start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
## the same as ``match``, but it returns the length of the match,
## if there is no match, -1 is returned. Note that a match length
## of zero can happen. It's possible that a suffix of `s` remains
## that does not belong to the match.
var c: TCaptures
var c: Captures
c.origStart = start
result = rawMatch(s, pattern, start, c)
proc find*(s: string, pattern: TPeg, matches: var openArray[string],
proc find*(s: string, pattern: Peg, matches: var openArray[string],
start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
## returns the starting position of ``pattern`` in ``s`` and the captured
## substrings in the array ``matches``. If it does not match, nothing
## is written into ``matches`` and -1 is returned.
var c: TCaptures
var c: Captures
c.origStart = start
for i in start .. s.len-1:
c.ml = 0
@ -801,14 +793,14 @@ proc find*(s: string, pattern: TPeg, matches: var openArray[string],
return -1
# could also use the pattern here: (!P .)* P
proc findBounds*(s: string, pattern: TPeg, matches: var openArray[string],
proc findBounds*(s: string, pattern: Peg, matches: var openArray[string],
start = 0): tuple[first, last: int] {.
nosideEffect, rtl, extern: "npegs$1Capture".} =
## returns the starting position and end position of ``pattern`` in ``s``
## and the captured
## substrings in the array ``matches``. If it does not match, nothing
## is written into ``matches`` and (-1,0) is returned.
var c: TCaptures
var c: Captures
c.origStart = start
for i in start .. s.len-1:
c.ml = 0
@ -818,19 +810,19 @@ proc findBounds*(s: string, pattern: TPeg, matches: var openArray[string],
return (i, i+L-1)
return (-1, 0)
proc find*(s: string, pattern: TPeg,
proc find*(s: string, pattern: Peg,
start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
## returns the starting position of ``pattern`` in ``s``. If it does not
## match, -1 is returned.
var c: TCaptures
var c: Captures
c.origStart = start
for i in start .. s.len-1:
if rawMatch(s, pattern, i, c) >= 0: return i
return -1
iterator findAll*(s: string, pattern: TPeg, start = 0): string =
iterator findAll*(s: string, pattern: Peg, start = 0): string =
## yields all matching *substrings* of `s` that match `pattern`.
var c: TCaptures
var c: Captures
c.origStart = start
var i = start
while i < s.len:
@ -842,7 +834,7 @@ iterator findAll*(s: string, pattern: TPeg, start = 0): string =
yield substr(s, i, i+L-1)
inc(i, L)
proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {.
proc findAll*(s: string, pattern: Peg, start = 0): seq[string] {.
nosideEffect, rtl, extern: "npegs$1".} =
## returns all matching *substrings* of `s` that match `pattern`.
## If it does not match, @[] is returned.
@ -851,11 +843,11 @@ proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {.
when not defined(nimhygiene):
{.pragma: inject.}
template `=~`*(s: string, pattern: TPeg): bool =
template `=~`*(s: string, pattern: Peg): bool =
## This calls ``match`` with an implicit declared ``matches`` array that
## can be used in the scope of the ``=~`` call:
##
## .. code-block:: nimrod
## .. code-block:: nim
##
## if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}":
## # matches a key=value pair:
@ -876,46 +868,46 @@ template `=~`*(s: string, pattern: TPeg): bool =
# ------------------------- more string handling ------------------------------
proc contains*(s: string, pattern: TPeg, start = 0): bool {.
proc contains*(s: string, pattern: Peg, start = 0): bool {.
nosideEffect, rtl, extern: "npegs$1".} =
## same as ``find(s, pattern, start) >= 0``
return find(s, pattern, start) >= 0
proc contains*(s: string, pattern: TPeg, matches: var openArray[string],
proc contains*(s: string, pattern: Peg, matches: var openArray[string],
start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
## same as ``find(s, pattern, matches, start) >= 0``
return find(s, pattern, matches, start) >= 0
proc startsWith*(s: string, prefix: TPeg, start = 0): bool {.
proc startsWith*(s: string, prefix: Peg, start = 0): bool {.
nosideEffect, rtl, extern: "npegs$1".} =
## returns true if `s` starts with the pattern `prefix`
result = matchLen(s, prefix, start) >= 0
proc endsWith*(s: string, suffix: TPeg, start = 0): bool {.
proc endsWith*(s: string, suffix: Peg, start = 0): bool {.
nosideEffect, rtl, extern: "npegs$1".} =
## returns true if `s` ends with the pattern `prefix`
var c: TCaptures
var c: Captures
c.origStart = start
for i in start .. s.len-1:
if rawMatch(s, suffix, i, c) == s.len - i: return true
proc replacef*(s: string, sub: TPeg, by: string): string {.
proc replacef*(s: string, sub: Peg, by: string): string {.
nosideEffect, rtl, extern: "npegs$1".} =
## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by`
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
##
## .. code-block:: nimrod
## .. code-block:: nim
## "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2")
##
## Results in:
##
## .. code-block:: nimrod
## .. code-block:: nim
##
## "var1<-keykey; val2<-key2key2"
result = ""
var i = 0
var caps: array[0..maxSubpatterns-1, string]
var c: TCaptures
var c: Captures
while i < s.len:
c.ml = 0
var x = rawMatch(s, sub, i, c)
@ -928,13 +920,13 @@ proc replacef*(s: string, sub: TPeg, by: string): string {.
inc(i, x)
add(result, substr(s, i))
proc replace*(s: string, sub: TPeg, by = ""): string {.
proc replace*(s: string, sub: Peg, by = ""): string {.
nosideEffect, rtl, extern: "npegs$1".} =
## Replaces `sub` in `s` by the string `by`. Captures cannot be accessed
## in `by`.
result = ""
var i = 0
var c: TCaptures
var c: Captures
while i < s.len:
var x = rawMatch(s, sub, i, c)
if x <= 0:
@ -946,13 +938,13 @@ proc replace*(s: string, sub: TPeg, by = ""): string {.
add(result, substr(s, i))
proc parallelReplace*(s: string, subs: varargs[
tuple[pattern: TPeg, repl: string]]): string {.
tuple[pattern: Peg, repl: string]]): string {.
nosideEffect, rtl, extern: "npegs$1".} =
## Returns a modified copy of `s` with the substitutions in `subs`
## applied in parallel.
result = ""
var i = 0
var c: TCaptures
var c: Captures
var caps: array[0..maxSubpatterns-1, string]
while i < s.len:
block searchSubs:
@ -970,7 +962,7 @@ proc parallelReplace*(s: string, subs: varargs[
add(result, substr(s, i))
proc transformFile*(infile, outfile: string,
subs: varargs[tuple[pattern: TPeg, repl: string]]) {.
subs: varargs[tuple[pattern: Peg, repl: string]]) {.
rtl, extern: "npegs$1".} =
## reads in the file `infile`, performs a parallel replacement (calls
## `parallelReplace`) and writes back to `outfile`. Raises ``EIO`` if an
@ -978,25 +970,25 @@ proc transformFile*(infile, outfile: string,
var x = readFile(infile).string
writeFile(outfile, x.parallelReplace(subs))
iterator split*(s: string, sep: TPeg): string =
iterator split*(s: string, sep: Peg): string =
## Splits the string `s` into substrings.
##
## Substrings are separated by the PEG `sep`.
## Examples:
##
## .. code-block:: nimrod
## .. code-block:: nim
## for word in split("00232this02939is39an22example111", peg"\d+"):
## writeln(stdout, word)
##
## Results in:
##
## .. code-block:: nimrod
## .. code-block:: nim
## "this"
## "is"
## "an"
## "example"
##
var c: TCaptures
var c: Captures
var
first = 0
last = 0
@ -1013,7 +1005,7 @@ iterator split*(s: string, sep: TPeg): string =
if first < last:
yield substr(s, first, last-1)
proc split*(s: string, sep: TPeg): seq[string] {.
proc split*(s: string, sep: Peg): seq[string] {.
nosideEffect, rtl, extern: "npegs$1".} =
## Splits the string `s` into substrings.
accumulateResult(split(s, sep))
@ -1060,7 +1052,7 @@ type
charset: set[char] ## if kind == tkCharSet
index: int ## if kind == tkBackref
TPegLexer {.inheritable.} = object ## the lexer object.
PegLexer {.inheritable.} = object ## the lexer object.
bufpos: int ## the current position within the buffer
buf: cstring ## the buffer itself
LineNumber: int ## the current line number
@ -1076,20 +1068,20 @@ const
"@", "built-in", "escaped", "$", "$", "^"
]
proc handleCR(L: var TPegLexer, pos: int): int =
proc handleCR(L: var PegLexer, pos: int): int =
assert(L.buf[pos] == '\c')
inc(L.linenumber)
result = pos+1
if L.buf[result] == '\L': inc(result)
L.lineStart = result
proc handleLF(L: var TPegLexer, pos: int): int =
proc handleLF(L: var PegLexer, pos: int): int =
assert(L.buf[pos] == '\L')
inc(L.linenumber)
result = pos+1
L.lineStart = result
proc init(L: var TPegLexer, input, filename: string, line = 1, col = 0) =
proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) =
L.buf = input
L.bufpos = 0
L.lineNumber = line
@ -1097,18 +1089,18 @@ proc init(L: var TPegLexer, input, filename: string, line = 1, col = 0) =
L.lineStart = 0
L.filename = filename
proc getColumn(L: TPegLexer): int {.inline.} =
proc getColumn(L: PegLexer): int {.inline.} =
result = abs(L.bufpos - L.lineStart) + L.colOffset
proc getLine(L: TPegLexer): int {.inline.} =
proc getLine(L: PegLexer): int {.inline.} =
result = L.linenumber
proc errorStr(L: TPegLexer, msg: string, line = -1, col = -1): string =
proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string =
var line = if line < 0: getLine(L) else: line
var col = if col < 0: getColumn(L) else: col
result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg]
proc handleHexChar(c: var TPegLexer, xi: var int) =
proc handleHexChar(c: var PegLexer, xi: var int) =
case c.buf[c.bufpos]
of '0'..'9':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
@ -1121,7 +1113,7 @@ proc handleHexChar(c: var TPegLexer, xi: var int) =
inc(c.bufpos)
else: discard
proc getEscapedChar(c: var TPegLexer, tok: var TToken) =
proc getEscapedChar(c: var PegLexer, tok: var TToken) =
inc(c.bufpos)
case c.buf[c.bufpos]
of 'r', 'R', 'c', 'C':
@ -1173,7 +1165,7 @@ proc getEscapedChar(c: var TPegLexer, tok: var TToken) =
add(tok.literal, c.buf[c.bufpos])
inc(c.bufpos)
proc skip(c: var TPegLexer) =
proc skip(c: var PegLexer) =
var pos = c.bufpos
var buf = c.buf
while true:
@ -1192,7 +1184,7 @@ proc skip(c: var TPegLexer) =
break # EndOfFile also leaves the loop
c.bufpos = pos
proc getString(c: var TPegLexer, tok: var TToken) =
proc getString(c: var PegLexer, tok: var TToken) =
tok.kind = tkStringLit
var pos = c.bufPos + 1
var buf = c.buf
@ -1214,7 +1206,7 @@ proc getString(c: var TPegLexer, tok: var TToken) =
inc(pos)
c.bufpos = pos
proc getDollar(c: var TPegLexer, tok: var TToken) =
proc getDollar(c: var PegLexer, tok: var TToken) =
var pos = c.bufPos + 1
var buf = c.buf
if buf[pos] in {'0'..'9'}:
@ -1227,7 +1219,7 @@ proc getDollar(c: var TPegLexer, tok: var TToken) =
tok.kind = tkDollar
c.bufpos = pos
proc getCharSet(c: var TPegLexer, tok: var TToken) =
proc getCharSet(c: var PegLexer, tok: var TToken) =
tok.kind = tkCharSet
tok.charset = {}
var pos = c.bufPos + 1
@ -1278,7 +1270,7 @@ proc getCharSet(c: var TPegLexer, tok: var TToken) =
c.bufpos = pos
if caret: tok.charset = {'\1'..'\xFF'} - tok.charset
proc getSymbol(c: var TPegLexer, tok: var TToken) =
proc getSymbol(c: var PegLexer, tok: var TToken) =
var pos = c.bufpos
var buf = c.buf
while true:
@ -1288,7 +1280,7 @@ proc getSymbol(c: var TPegLexer, tok: var TToken) =
c.bufpos = pos
tok.kind = tkIdentifier
proc getBuiltin(c: var TPegLexer, tok: var TToken) =
proc getBuiltin(c: var PegLexer, tok: var TToken) =
if c.buf[c.bufpos+1] in strutils.Letters:
inc(c.bufpos)
getSymbol(c, tok)
@ -1297,7 +1289,7 @@ proc getBuiltin(c: var TPegLexer, tok: var TToken) =
tok.kind = tkEscaped
getEscapedChar(c, tok) # may set tok.kind to tkInvalid
proc getTok(c: var TPegLexer, tok: var TToken) =
proc getTok(c: var PegLexer, tok: var TToken) =
tok.kind = tkInvalid
tok.modifier = modNone
setLen(tok.literal, 0)
@ -1403,7 +1395,7 @@ proc getTok(c: var TPegLexer, tok: var TToken) =
add(tok.literal, c.buf[c.bufpos])
inc(c.bufpos)
proc arrowIsNextTok(c: TPegLexer): bool =
proc arrowIsNextTok(c: PegLexer): bool =
# the only look ahead we need
var pos = c.bufpos
while c.buf[pos] in {'\t', ' '}: inc(pos)
@ -1414,31 +1406,31 @@ proc arrowIsNextTok(c: TPegLexer): bool =
type
EInvalidPeg* = object of EInvalidValue ## raised if an invalid
## PEG has been detected
TPegParser = object of TPegLexer ## the PEG parser object
PegParser = object of PegLexer ## the PEG parser object
tok: TToken
nonterms: seq[PNonTerminal]
modifier: TModifier
captures: int
identIsVerbatim: bool
skip: TPeg
skip: Peg
proc pegError(p: TPegParser, msg: string, line = -1, col = -1) =
proc pegError(p: PegParser, msg: string, line = -1, col = -1) =
var e: ref EInvalidPeg
new(e)
e.msg = errorStr(p, msg, line, col)
raise e
proc getTok(p: var TPegParser) =
proc getTok(p: var PegParser) =
getTok(p, p.tok)
if p.tok.kind == tkInvalid: pegError(p, "invalid token")
proc eat(p: var TPegParser, kind: TTokKind) =
proc eat(p: var PegParser, kind: TTokKind) =
if p.tok.kind == kind: getTok(p)
else: pegError(p, tokKindToStr[kind] & " expected")
proc parseExpr(p: var TPegParser): TPeg
proc parseExpr(p: var PegParser): Peg
proc getNonTerminal(p: var TPegParser, name: string): PNonTerminal =
proc getNonTerminal(p: var PegParser, name: string): PNonTerminal =
for i in 0..high(p.nonterms):
result = p.nonterms[i]
if cmpIgnoreStyle(result.name, name) == 0: return
@ -1446,19 +1438,19 @@ proc getNonTerminal(p: var TPegParser, name: string): PNonTerminal =
result = newNonTerminal(name, getLine(p), getColumn(p))
add(p.nonterms, result)
proc modifiedTerm(s: string, m: TModifier): TPeg =
proc modifiedTerm(s: string, m: TModifier): Peg =
case m
of modNone, modVerbatim: result = term(s)
of modIgnoreCase: result = termIgnoreCase(s)
of modIgnoreStyle: result = termIgnoreStyle(s)
proc modifiedBackref(s: int, m: TModifier): TPeg =
proc modifiedBackref(s: int, m: TModifier): Peg =
case m
of modNone, modVerbatim: result = backref(s)
of modIgnoreCase: result = backrefIgnoreCase(s)
of modIgnoreStyle: result = backrefIgnoreStyle(s)
proc builtin(p: var TPegParser): TPeg =
proc builtin(p: var PegParser): Peg =
# do not use "y", "skip" or "i" as these would be ambiguous
case p.tok.literal
of "n": result = newLine()
@ -1478,11 +1470,11 @@ proc builtin(p: var TPegParser): TPeg =
of "white": result = unicodeWhitespace()
else: pegError(p, "unknown built-in: " & p.tok.literal)
proc token(terminal: TPeg, p: TPegParser): TPeg =
proc token(terminal: Peg, p: PegParser): Peg =
if p.skip.kind == pkEmpty: result = terminal
else: result = sequence(p.skip, terminal)
proc primary(p: var TPegParser): TPeg =
proc primary(p: var PegParser): Peg =
case p.tok.kind
of tkAmp:
getTok(p)
@ -1571,7 +1563,7 @@ proc primary(p: var TPegParser): TPeg =
getTok(p)
else: break
proc seqExpr(p: var TPegParser): TPeg =
proc seqExpr(p: var PegParser): Peg =
result = primary(p)
while true:
case p.tok.kind
@ -1585,13 +1577,13 @@ proc seqExpr(p: var TPegParser): TPeg =
else: break
else: break
proc parseExpr(p: var TPegParser): TPeg =
proc parseExpr(p: var PegParser): Peg =
result = seqExpr(p)
while p.tok.kind == tkBar:
getTok(p)
result = result / seqExpr(p)
proc parseRule(p: var TPegParser): PNonTerminal =
proc parseRule(p: var PegParser): PNonTerminal =
if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
result = getNonTerminal(p, p.tok.literal)
if ntDeclared in result.flags:
@ -1605,7 +1597,7 @@ proc parseRule(p: var TPegParser): PNonTerminal =
else:
pegError(p, "rule expected, but found: " & p.tok.literal)
proc rawParse(p: var TPegParser): TPeg =
proc rawParse(p: var PegParser): Peg =
## parses a rule or a PEG expression
while p.tok.kind == tkBuiltin:
case p.tok.literal
@ -1635,12 +1627,12 @@ proc rawParse(p: var TPegParser): TPeg =
elif ntUsed notin nt.flags and i > 0:
pegError(p, "unused rule: " & nt.name, nt.line, nt.col)
proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): TPeg =
## constructs a TPeg object from `pattern`. `filename`, `line`, `col` are
proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): Peg =
## constructs a Peg object from `pattern`. `filename`, `line`, `col` are
## used for error messages, but they only provide start offsets. `parsePeg`
## keeps track of line and column numbers within `pattern`.
var p: TPegParser
init(TPegLexer(p), pattern, filename, line, col)
var p: PegParser
init(PegLexer(p), pattern, filename, line, col)
p.tok.kind = tkInvalid
p.tok.modifier = modNone
p.tok.literal = ""
@ -1650,8 +1642,8 @@ proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): TPeg =
getTok(p)
result = rawParse(p)
proc peg*(pattern: string): TPeg =
## constructs a TPeg object from the `pattern`. The short name has been
proc peg*(pattern: string): Peg =
## constructs a Peg object from the `pattern`. The short name has been
## chosen to encourage its use as a raw string modifier::
##
## peg"{\ident} \s* '=' \s* {.*}"
@ -1704,7 +1696,7 @@ when isMainModule:
expr.rule = sequence(capture(ident), *sequence(
nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
var c: TCaptures
var c: Captures
var s = "a+b + c +d+e+f"
assert rawMatch(s, expr.rule, 0, c) == len(s)
var a = ""

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2013 Robert Persson
#
# See the file "copying.txt", included in this
@ -12,10 +12,11 @@ import strutils
import numeric
type
TPoly* = object
cofs:seq[float]
Poly* = object
cofs:seq[float]
{.deprecated: [TPoly: Poly].}
proc degree*(p:TPoly):int=
## Returns the degree of the polynomial,
## that is the number of coefficients-1
@ -104,7 +105,7 @@ proc `$` *(p:TPoly):string =
result="0"
proc derivative*(p:TPoly):TPoly=
proc derivative*(p: TPoly): TPoly=
## Returns a new polynomial, which is the derivative of `p`
newSeq[float](result.cofs,p.degree)
for idx in 0..high(result.cofs):
@ -310,10 +311,10 @@ proc getRangeForRoots(p:TPoly):tuple[xmin,xmax:float]=
var bound1,bound2:float
for i in countup(0,deg):
var c=abs(p.cofs[i]/d)
bound1=max(bound1,c+1.0)
bound2=bound2+c
var c=abs(p.cofs[i]/d)
bound1=max(bound1,c+1.0)
bound2=bound2+c
bound2=max(1.0,bound2)
result.xmax=min(bound1,bound2)
result.xmin= -result.xmax

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -28,7 +28,7 @@ else:
export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL,
EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET
export TSocketHandle, TSockaddr_in, TAddrinfo, INADDR_ANY, TSockAddr, TSockLen,
export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen,
inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto
export
@ -40,22 +40,22 @@ export
MSG_PEEK
type
TPort* = distinct uint16 ## port type
Port* = distinct uint16 ## port type
TDomain* = enum ## domain, which specifies the protocol family of the
Domain* = enum ## domain, which specifies the protocol family of the
## created socket. Other domains than those that are listed
## here are unsupported.
AF_UNIX, ## for local socket (using a file). Unsupported on Windows.
AF_INET = 2, ## for network protocol IPv4 or
AF_INET6 = 23 ## for network protocol IPv6.
TType* = enum ## second argument to `socket` proc
SockType* = enum ## second argument to `socket` proc
SOCK_STREAM = 1, ## reliable stream-oriented service or Stream Sockets
SOCK_DGRAM = 2, ## datagram service or Datagram Sockets
SOCK_RAW = 3, ## raw protocols atop the network layer.
SOCK_SEQPACKET = 5 ## reliable sequenced packet service
TProtocol* = enum ## third argument to `socket` proc
Protocol* = enum ## third argument to `socket` proc
IPPROTO_TCP = 6, ## Transmission control protocol.
IPPROTO_UDP = 17, ## User datagram protocol.
IPPROTO_IP, ## Internet protocol. Unsupported on Windows.
@ -63,19 +63,22 @@ type
IPPROTO_RAW, ## Raw IP Packets Protocol. Unsupported on Windows.
IPPROTO_ICMP ## Control message protocol. Unsupported on Windows.
TServent* {.pure, final.} = object ## information about a service
Servent* = object ## information about a service
name*: string
aliases*: seq[string]
port*: TPort
port*: Port
proto*: string
Thostent* {.pure, final.} = object ## information about a given host
Hostent* = object ## information about a given host
name*: string
aliases*: seq[string]
addrtype*: TDomain
addrtype*: Domain
length*: int
addrList*: seq[string]
{.deprecated: [TPort: Port, TDomain: Domain, TType: SockType,
TProtocol: Protocol, TServent: Servent, THostent: Hostent].}
when useWinVersion:
let
osInvalidSocket* = winlean.INVALID_SOCKET
@ -86,37 +89,37 @@ when useWinVersion:
FIONBIO* = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or
(102 shl 8) or 126
proc ioctlsocket*(s: TSocketHandle, cmd: clong,
proc ioctlsocket*(s: SocketHandle, cmd: clong,
argptr: ptr clong): cint {.
stdcall, importc: "ioctlsocket", dynlib: "ws2_32.dll".}
else:
let
osInvalidSocket* = posix.INVALID_SOCKET
proc `==`*(a, b: TPort): bool {.borrow.}
proc `==`*(a, b: Port): bool {.borrow.}
## ``==`` for ports.
proc `$`*(p: TPort): string {.borrow.}
proc `$`*(p: Port): string {.borrow.}
## returns the port number as a string
proc toInt*(domain: TDomain): cint
proc toInt*(domain: Domain): cint
## Converts the TDomain enum to a platform-dependent ``cint``.
proc toInt*(typ: TType): cint
proc toInt*(typ: SockType): cint
## Converts the TType enum to a platform-dependent ``cint``.
proc toInt*(p: TProtocol): cint
proc toInt*(p: Protocol): cint
## Converts the TProtocol enum to a platform-dependent ``cint``.
when not useWinVersion:
proc toInt(domain: TDomain): cint =
proc toInt(domain: Domain): cint =
case domain
of AF_UNIX: result = posix.AF_UNIX
of AF_INET: result = posix.AF_INET
of AF_INET6: result = posix.AF_INET6
else: discard
proc toInt(typ: TType): cint =
proc toInt(typ: SockType): cint =
case typ
of SOCK_STREAM: result = posix.SOCK_STREAM
of SOCK_DGRAM: result = posix.SOCK_DGRAM
@ -124,7 +127,7 @@ when not useWinVersion:
of SOCK_RAW: result = posix.SOCK_RAW
else: discard
proc toInt(p: TProtocol): cint =
proc toInt(p: Protocol): cint =
case p
of IPPROTO_TCP: result = posix.IPPROTO_TCP
of IPPROTO_UDP: result = posix.IPPROTO_UDP
@ -135,22 +138,22 @@ when not useWinVersion:
else: discard
else:
proc toInt(domain: TDomain): cint =
proc toInt(domain: Domain): cint =
result = toU16(ord(domain))
proc toInt(typ: TType): cint =
proc toInt(typ: SockType): cint =
result = cint(ord(typ))
proc toInt(p: TProtocol): cint =
proc toInt(p: Protocol): cint =
result = cint(ord(p))
proc newRawSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
protocol: TProtocol = IPPROTO_TCP): TSocketHandle =
proc newRawSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
protocol: Protocol = IPPROTO_TCP): SocketHandle =
## Creates a new socket; returns `InvalidSocket` if an error occurs.
socket(toInt(domain), toInt(typ), toInt(protocol))
proc close*(socket: TSocketHandle) =
proc close*(socket: SocketHandle) =
## closes a socket.
when useWinVersion:
discard winlean.closeSocket(socket)
@ -159,10 +162,10 @@ proc close*(socket: TSocketHandle) =
# TODO: These values should not be discarded. An EOS should be raised.
# http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times
proc bindAddr*(socket: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint =
proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint =
result = bindSocket(socket, name, namelen)
proc listen*(socket: TSocketHandle, backlog = SOMAXCONN): cint {.tags: [FReadIO].} =
proc listen*(socket: SocketHandle, backlog = SOMAXCONN): cint {.tags: [FReadIO].} =
## Marks ``socket`` as accepting connections.
## ``Backlog`` specifies the maximum length of the
## queue of pending connections.
@ -171,12 +174,12 @@ proc listen*(socket: TSocketHandle, backlog = SOMAXCONN): cint {.tags: [FReadIO]
else:
result = posix.listen(socket, cint(backlog))
proc getAddrInfo*(address: string, port: TPort, af: TDomain = AF_INET, typ: TType = SOCK_STREAM,
prot: TProtocol = IPPROTO_TCP): ptr TAddrInfo =
proc getAddrInfo*(address: string, port: Port, af: Domain = AF_INET, typ: SockType = SOCK_STREAM,
prot: Protocol = IPPROTO_TCP): ptr AddrInfo =
##
##
## **Warning**: The resulting ``ptr TAddrInfo`` must be freed using ``dealloc``!
var hints: TAddrInfo
var hints: AddrInfo
result = nil
hints.ai_family = toInt(af)
hints.ai_socktype = toInt(typ)
@ -184,11 +187,11 @@ proc getAddrInfo*(address: string, port: TPort, af: TDomain = AF_INET, typ: TTyp
var gaiResult = getAddrInfo(address, $port, addr(hints), result)
if gaiResult != 0'i32:
when useWinVersion:
osError(osLastError())
raiseOSError(osLastError())
else:
raise newException(EOS, $gai_strerror(gaiResult))
proc dealloc*(ai: ptr TAddrInfo) =
proc dealloc*(ai: ptr AddrInfo) =
freeaddrinfo(ai)
proc ntohl*(x: int32): int32 =
@ -220,7 +223,7 @@ proc htons*(x: int16): int16 =
## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
result = rawsockets.ntohs(x)
proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
proc getServByName*(name, proto: string): Servent {.tags: [FReadIO].} =
## Searches the database from the beginning and finds the first entry for
## which the service name specified by ``name`` matches the s_name member
## and the protocol name specified by ``proto`` matches the s_proto member.
@ -233,10 +236,10 @@ proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
if s == nil: raise newException(EOS, "Service not found.")
result.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = TPort(s.s_port)
result.port = Port(s.s_port)
result.proto = $s.s_proto
proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} =
proc getServByPort*(port: Port, proto: string): Servent {.tags: [FReadIO].} =
## Searches the database from the beginning and finds the first entry for
## which the port specified by ``port`` matches the s_port member and the
## protocol name specified by ``proto`` matches the s_proto member.
@ -249,28 +252,28 @@ proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} =
if s == nil: raise newException(EOS, "Service not found.")
result.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = TPort(s.s_port)
result.port = Port(s.s_port)
result.proto = $s.s_proto
proc getHostByAddr*(ip: string): Thostent {.tags: [FReadIO].} =
proc getHostByAddr*(ip: string): Hostent {.tags: [FReadIO].} =
## This function will lookup the hostname of an IP Address.
var myaddr: TInAddr
var myaddr: InAddr
myaddr.s_addr = inet_addr(ip)
when useWinVersion:
var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
cint(rawsockets.AF_INET))
if s == nil: osError(osLastError())
if s == nil: raiseOSError(osLastError())
else:
var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSocklen,
var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen,
cint(posix.AF_INET))
if s == nil:
raise newException(EOS, $hstrerror(h_errno))
result.name = $s.h_name
result.aliases = cstringArrayToSeq(s.h_aliases)
when useWinVersion:
result.addrtype = TDomain(s.h_addrtype)
when useWinVersion:
result.addrtype = Domain(s.h_addrtype)
else:
if s.h_addrtype == posix.AF_INET:
result.addrtype = AF_INET
@ -281,17 +284,17 @@ proc getHostByAddr*(ip: string): Thostent {.tags: [FReadIO].} =
result.addrList = cstringArrayToSeq(s.h_addr_list)
result.length = int(s.h_length)
proc getHostByName*(name: string): Thostent {.tags: [FReadIO].} =
proc getHostByName*(name: string): Hostent {.tags: [FReadIO].} =
## This function will lookup the IP address of a hostname.
when useWinVersion:
var s = winlean.gethostbyname(name)
else:
var s = posix.gethostbyname(name)
if s == nil: osError(osLastError())
if s == nil: raiseOSError(osLastError())
result.name = $s.h_name
result.aliases = cstringArrayToSeq(s.h_aliases)
when useWinVersion:
result.addrtype = TDomain(s.h_addrtype)
when useWinVersion:
result.addrtype = Domain(s.h_addrtype)
else:
if s.h_addrtype == posix.AF_INET:
result.addrtype = AF_INET
@ -302,69 +305,69 @@ proc getHostByName*(name: string): Thostent {.tags: [FReadIO].} =
result.addrList = cstringArrayToSeq(s.h_addr_list)
result.length = int(s.h_length)
proc getSockName*(socket: TSocketHandle): TPort =
proc getSockName*(socket: SocketHandle): Port =
## returns the socket's associated port number.
var name: Tsockaddr_in
var name: Sockaddr_in
when useWinVersion:
name.sin_family = int16(ord(AF_INET))
else:
name.sin_family = posix.AF_INET
#name.sin_port = htons(cint16(port))
#name.sin_addr.s_addr = htonl(INADDR_ANY)
var namelen = sizeof(name).TSocklen
if getsockname(socket, cast[ptr TSockAddr](addr(name)),
var namelen = sizeof(name).Socklen
if getsockname(socket, cast[ptr SockAddr](addr(name)),
addr(namelen)) == -1'i32:
osError(osLastError())
result = TPort(rawsockets.ntohs(name.sin_port))
raiseOSError(osLastError())
result = Port(rawsockets.ntohs(name.sin_port))
proc getSockOptInt*(socket: TSocketHandle, level, optname: int): int {.
proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {.
tags: [FReadIO].} =
## getsockopt for integer options.
var res: cint
var size = sizeof(res).TSocklen
var size = sizeof(res).Socklen
if getsockopt(socket, cint(level), cint(optname),
addr(res), addr(size)) < 0'i32:
osError(osLastError())
raiseOSError(osLastError())
result = int(res)
proc setSockOptInt*(socket: TSocketHandle, level, optname, optval: int) {.
proc setSockOptInt*(socket: SocketHandle, level, optname, optval: int) {.
tags: [FWriteIO].} =
## setsockopt for integer options.
var value = cint(optval)
if setsockopt(socket, cint(level), cint(optname), addr(value),
sizeof(value).TSocklen) < 0'i32:
osError(osLastError())
sizeof(value).Socklen) < 0'i32:
raiseOSError(osLastError())
proc setBlocking*(s: TSocketHandle, blocking: bool) =
proc setBlocking*(s: SocketHandle, blocking: bool) =
## Sets blocking mode on socket.
##
## Raises EOS on error.
when useWinVersion:
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
if ioctlsocket(s, FIONBIO, addr(mode)) == -1:
osError(osLastError())
raiseOSError(osLastError())
else: # BSD sockets
var x: int = fcntl(s, F_GETFL, 0)
if x == -1:
osError(osLastError())
raiseOSError(osLastError())
else:
var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
if fcntl(s, F_SETFL, mode) == -1:
osError(osLastError())
raiseOSError(osLastError())
proc timeValFromMilliseconds(timeout = 500): Ttimeval =
proc timeValFromMilliseconds(timeout = 500): Timeval =
if timeout != -1:
var seconds = timeout div 1000
result.tv_sec = seconds.int32
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
proc createFdSet(fd: var TFdSet, s: seq[TSocketHandle], m: var int) =
proc createFdSet(fd: var FdSet, s: seq[SocketHandle], m: var int) =
FD_ZERO(fd)
for i in items(s):
m = max(m, int(i))
FD_SET(i, fd)
proc pruneSocketSet(s: var seq[TSocketHandle], fd: var TFdSet) =
proc pruneSocketSet(s: var seq[SocketHandle], fd: var FdSet) =
var i = 0
var L = s.len
while i < L:
@ -375,7 +378,7 @@ proc pruneSocketSet(s: var seq[TSocketHandle], fd: var TFdSet) =
inc(i)
setLen(s, L)
proc select*(readfds: var seq[TSocketHandle], timeout = 500): int =
proc select*(readfds: var seq[SocketHandle], timeout = 500): int =
## Traditional select function. This function will return the number of
## sockets that are ready to be read from, written to, or which have errors.
## If there are none; 0 is returned.
@ -396,7 +399,7 @@ proc select*(readfds: var seq[TSocketHandle], timeout = 500): int =
pruneSocketSet(readfds, (rd))
proc selectWrite*(writefds: var seq[TSocketHandle],
proc selectWrite*(writefds: var seq[SocketHandle],
timeout = 500): int {.tags: [FReadIO].} =
## When a socket in ``writefds`` is ready to be written to then a non-zero
## value will be returned specifying the count of the sockets which can be
@ -405,7 +408,7 @@ proc selectWrite*(writefds: var seq[TSocketHandle],
##
## ``timeout`` is specified in miliseconds and ``-1`` can be specified for
## an unlimited time.
var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout)
var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
var wr: TFdSet
var m = 0
@ -419,5 +422,5 @@ proc selectWrite*(writefds: var seq[TSocketHandle],
pruneSocketSet(writefds, (wr))
when defined(Windows):
var wsa: TWSADATA
if WSAStartup(0x0101'i16, addr wsa) != 0: osError(osLastError())
var wsa: WSADATA
if WSAStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError())

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -20,36 +20,40 @@ const
redisNil* = "\0\0"
type
PPipeline = ref object
Pipeline = ref object
enabled: bool
buffer: string
expected: int ## number of replies expected if pipelined
type
TSendMode = enum
SendMode = enum
normal, pipelined, multiple
type
TRedis* {.pure, final.} = object
Redis* = object
socket: TSocket
connected: bool
pipeline: PPipeline
pipeline: Pipeline
TRedisStatus* = string
TRedisInteger* = biggestInt
TRedisString* = string ## Bulk reply
TRedisList* = seq[TRedisString] ## Multi-bulk reply
RedisStatus* = string
RedisInteger* = BiggestInt
RedisString* = string ## Bulk reply
RedisList* = seq[RedisString] ## Multi-bulk reply
EInvalidReply* = object of ESynch ## Invalid reply from redis
ERedis* = object of ESynch ## Error in redis
ReplyError* = object of IOError ## Invalid reply from redis
RedisError* = object of IOError ## Error in redis
proc newPipeline(): PPipeline =
{.deprecated: [TSendMode: SendMode, TRedis: Redis, TRedisStatus: RedisStatus,
TRedisInteger: RedisInteger, TRedisString: RedisString,
TRedisList: RedistList, EInvalidReply: ReplyError, ERedis: RedisError].}
proc newPipeline(): Pipeline =
new(result)
result.buffer = ""
result.enabled = false
result.expected = 0
proc open*(host = "localhost", port = 6379.TPort): TRedis =
proc open*(host = "localhost", port = 6379.Port): Redis =
## Opens a connection to the redis server.
result.socket = socket(buffered = false)
if result.socket == InvalidSocket:
@ -58,24 +62,24 @@ proc open*(host = "localhost", port = 6379.TPort): TRedis =
result.pipeline = newPipeline()
proc raiseInvalidReply(expected, got: char) =
raise newException(EInvalidReply,
raise newException(ReplyError,
"Expected '$1' at the beginning of a status reply got '$2'" %
[$expected, $got])
proc raiseNoOK(status: string, pipelineEnabled:bool) =
proc raiseNoOK(status: string, pipelineEnabled: bool) =
if pipelineEnabled and not (status == "QUEUED" or status == "PIPELINED"):
raise newException(EInvalidReply, "Expected \"QUEUED\" or \"PIPELINED\" got \"$1\"" % status)
elif not pipelineEnabled and status != "OK":
raise newException(EInvalidReply, "Expected \"OK\" got \"$1\"" % status)
template readSocket(r: TRedis, dummyVal:expr): stmt =
var line {.inject.} :TaintedString = ""
template readSocket(r: Redis, dummyVal:expr): stmt =
var line {.inject.}: TaintedString = ""
if r.pipeline.enabled:
return dummyVal
else:
readLine(r.socket, line)
proc parseStatus(r: TRedis, line: string = ""): TRedisStatus =
proc parseStatus(r: Redis, line: string = ""): RedisStatus =
if r.pipeline.enabled:
return "PIPELINED"

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2011 Philippe Lhoste
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -30,13 +30,15 @@ var
cacheEnabled = false
type
PRope* = ref TRope ## empty rope is represented by nil
TRope {.acyclic, final, pure.} = object
left, right: PRope
Rope* = ref RopeObj ## empty rope is represented by nil
RopeObj {.acyclic.} = object
left, right: Rope
length: int
data: string # != nil if a leaf
proc isConc(r: PRope): bool {.inline.} = return isNil(r.data)
{.deprecated: [PRope: Rope].}
proc isConc(r: Rope): bool {.inline.} = return isNil(r.data)
# Note that the left and right pointers are not needed for leafs.
# Leaves have relatively high memory overhead (~30 bytes on a 32
@ -46,25 +48,25 @@ proc isConc(r: PRope): bool {.inline.} = return isNil(r.data)
# performance. But for the caching tree we use the leaf's left and right
# pointers.
proc len*(a: PRope): int {.rtl, extern: "nro$1".} =
proc len*(a: Rope): int {.rtl, extern: "nro$1".} =
## the rope's length
if a == nil: result = 0
else: result = a.length
proc newRope(): PRope = new(result)
proc newRope(data: string): PRope =
proc newRope(): Rope = new(result)
proc newRope(data: string): Rope =
new(result)
result.length = len(data)
result.data = data
var
cache {.threadvar.}: PRope # the root of the cache tree
N {.threadvar.}: PRope # dummy rope needed for splay algorithm
cache {.threadvar.}: Rope # the root of the cache tree
N {.threadvar.}: Rope # dummy rope needed for splay algorithm
when countCacheMisses:
var misses, hits: int
proc splay(s: string, tree: PRope, cmpres: var int): PRope =
proc splay(s: string, tree: Rope, cmpres: var int): Rope =
var c: int
var t = tree
N.left = nil
@ -102,7 +104,7 @@ proc splay(s: string, tree: PRope, cmpres: var int): PRope =
t.right = N.left
result = t
proc insertInCache(s: string, tree: PRope): PRope =
proc insertInCache(s: string, tree: Rope): Rope =
var t = tree
if t == nil:
result = newRope(s)
@ -128,7 +130,7 @@ proc insertInCache(s: string, tree: PRope): PRope =
result.left = t
t.right = nil
proc rope*(s: string): PRope {.rtl, extern: "nro$1Str".} =
proc rope*(s: string): Rope {.rtl, extern: "nro$1Str".} =
## Converts a string to a rope.
if s.len == 0:
result = nil
@ -138,11 +140,11 @@ proc rope*(s: string): PRope {.rtl, extern: "nro$1Str".} =
else:
result = newRope(s)
proc rope*(i: BiggestInt): PRope {.rtl, extern: "nro$1BiggestInt".} =
proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} =
## Converts an int to a rope.
result = rope($i)
proc rope*(f: BiggestFloat): PRope {.rtl, extern: "nro$1BiggestFloat".} =
proc rope*(f: BiggestFloat): Rope {.rtl, extern: "nro$1BiggestFloat".} =
## Converts a float to a rope.
result = rope($f)
@ -156,7 +158,7 @@ proc disableCache*() {.rtl, extern: "nro$1".} =
cache = nil
cacheEnabled = false
proc `&`*(a, b: PRope): PRope {.rtl, extern: "nroConcRopeRope".} =
proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} =
## the concatenation operator for ropes.
if a == nil:
result = b
@ -176,27 +178,27 @@ proc `&`*(a, b: PRope): PRope {.rtl, extern: "nroConcRopeRope".} =
result.left = a
result.right = b
proc `&`*(a: PRope, b: string): PRope {.rtl, extern: "nroConcRopeStr".} =
proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} =
## the concatenation operator for ropes.
result = a & rope(b)
proc `&`*(a: string, b: PRope): PRope {.rtl, extern: "nroConcStrRope".} =
proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} =
## the concatenation operator for ropes.
result = rope(a) & b
proc `&`*(a: openarray[PRope]): PRope {.rtl, extern: "nroConcOpenArray".} =
proc `&`*(a: openarray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} =
## the concatenation operator for an openarray of ropes.
for i in countup(0, high(a)): result = result & a[i]
proc add*(a: var PRope, b: PRope) {.rtl, extern: "nro$1Rope".} =
proc add*(a: var Rope, b: Rope) {.rtl, extern: "nro$1Rope".} =
## adds `b` to the rope `a`.
a = a & b
proc add*(a: var PRope, b: string) {.rtl, extern: "nro$1Str".} =
proc add*(a: var Rope, b: string) {.rtl, extern: "nro$1Str".} =
## adds `b` to the rope `a`.
a = a & b
proc `[]`*(r: PRope, i: int): char {.rtl, extern: "nroCharAt".} =
proc `[]`*(r: Rope, i: int): char {.rtl, extern: "nroCharAt".} =
## returns the character at position `i` in the rope `r`. This is quite
## expensive! Worst-case: O(n). If ``i >= r.len``, ``\0`` is returned.
var x = r
@ -213,7 +215,7 @@ proc `[]`*(r: PRope, i: int): char {.rtl, extern: "nroCharAt".} =
x = x.right
dec(j, x.len)
iterator leaves*(r: PRope): string =
iterator leaves*(r: Rope): string =
## iterates over any leaf string in the rope `r`.
if r != nil:
var stack = @[r]
@ -226,16 +228,16 @@ iterator leaves*(r: PRope): string =
assert(it.data != nil)
yield it.data
iterator items*(r: PRope): char =
iterator items*(r: Rope): char =
## iterates over any character in the rope `r`.
for s in leaves(r):
for c in items(s): yield c
proc write*(f: TFile, r: PRope) {.rtl, extern: "nro$1".} =
proc write*(f: TFile, r: Rope) {.rtl, extern: "nro$1".} =
## writes a rope to a file.
for s in leaves(r): write(f, s)
proc `$`*(r: PRope): string {.rtl, extern: "nroToString".}=
proc `$`*(r: Rope): string {.rtl, extern: "nroToString".}=
## converts a rope back to a string.
result = newString(r.len)
setLen(result, 0)
@ -245,11 +247,11 @@ when false:
# Format string caching seems reasonable: All leaves can be shared and format
# string parsing has to be done only once. A compiled format string is stored
# as a rope. A negative length is used for the index into the args array.
proc compiledArg(idx: int): PRope =
proc compiledArg(idx: int): Rope =
new(result)
result.length = -idx
proc compileFrmt(frmt: string): PRope =
proc compileFrmt(frmt: string): Rope =
var i = 0
var length = len(frmt)
result = nil
@ -289,7 +291,7 @@ when false:
if i - 1 >= start:
add(result, substr(frmt, start, i-1))
proc `%`*(frmt: string, args: openarray[PRope]): PRope {.
proc `%`*(frmt: string, args: openarray[Rope]): Rope {.
rtl, extern: "nroFormat".} =
## `%` substitution operator for ropes. Does not support the ``$identifier``
## nor ``${identifier}`` notations.
@ -332,12 +334,12 @@ proc `%`*(frmt: string, args: openarray[PRope]): PRope {.
if i - 1 >= start:
add(result, substr(frmt, start, i - 1))
proc addf*(c: var PRope, frmt: string, args: openarray[PRope]) {.
proc addf*(c: var Rope, frmt: string, args: openarray[Rope]) {.
rtl, extern: "nro$1".} =
## shortcut for ``add(c, frmt % args)``.
add(c, frmt % args)
proc equalsFile*(r: PRope, f: TFile): bool {.rtl, extern: "nro$1File".} =
proc equalsFile*(r: Rope, f: TFile): bool {.rtl, extern: "nro$1File".} =
## returns true if the contents of the file `f` equal `r`.
var bufSize = 1024 # reasonable start value
var buf = alloc(BufSize)
@ -352,7 +354,7 @@ proc equalsFile*(r: PRope, f: TFile): bool {.rtl, extern: "nro$1File".} =
result = readBuffer(f, buf, 1) == 0 # really at the end of file?
dealloc(buf)
proc equalsFile*(r: PRope, f: string): bool {.rtl, extern: "nro$1Str".} =
proc equalsFile*(r: Rope, f: string): bool {.rtl, extern: "nro$1Str".} =
## returns true if the contents of the file `f` equal `r`. If `f` does not
## exist, false is returned.
var bin: TFile

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2013 Andreas Rumpf, Dominik Picheta
#
# See the file "copying.txt", included in this
@ -9,13 +9,13 @@
## This module implements helper procs for SCGI applications. Example:
##
## .. code-block:: Nimrod
## .. code-block:: Nim
##
## import strtabs, sockets, scgi
##
## var counter = 0
## proc handleRequest(client: TSocket, input: string,
## headers: PStringTable): bool {.procvar.} =
## proc handleRequest(client: Socket, input: string,
## headers: StringTableRef): bool {.procvar.} =
## inc(counter)
## client.writeStatusOkTextContent()
## client.send("Hello for the $#th time." % $counter & "\c\L")
@ -31,11 +31,11 @@ include "system/inclrtl"
import sockets, strutils, os, strtabs, asyncio
type
EScgi* = object of EIO ## the exception that is raised, if a SCGI error occurs
ScgiError* = object of IOError ## the exception that is raised, if a SCGI error occurs
proc scgiError*(msg: string) {.noreturn.} =
## raises an EScgi exception with message `msg`.
var e: ref EScgi
proc raiseScgiError*(msg: string) {.noreturn.} =
## raises an ScgiError exception with message `msg`.
var e: ref ScgiError
new(e)
e.msg = msg
raise e
@ -45,7 +45,7 @@ proc parseWord(inp: string, outp: var string, start: int): int =
while inp[result] != '\0': inc(result)
outp = substr(inp, start, result-1)
proc parseHeaders(s: string, L: int): PStringTable =
proc parseHeaders(s: string, L: int): StringTableRef =
result = newStringTable()
var i = 0
while i < L:
@ -54,73 +54,77 @@ proc parseHeaders(s: string, L: int): PStringTable =
i = parseWord(s, val, i)+1
result[key] = val
if s[i] == ',': inc(i)
else: scgiError("',' after netstring expected")
else: raiseScgiError("',' after netstring expected")
proc recvChar(s: TSocket): char =
proc recvChar(s: Socket): char =
var c: char
if recv(s, addr(c), sizeof(c)) == sizeof(c):
result = c
type
TScgiState* = object of TObject ## SCGI state object
server: TSocket
ScgiState* = object of RootObj ## SCGI state object
server: Socket
bufLen: int
client*: TSocket ## the client socket to send data to
headers*: PStringTable ## the parsed headers
client*: Socket ## the client socket to send data to
headers*: StringTableRef ## the parsed headers
input*: string ## the input buffer
# Async
TClientMode = enum
ClientMode = enum
ClientReadChar, ClientReadHeaders, ClientReadContent
PAsyncClient = ref object
c: PAsyncSocket
mode: TClientMode
AsyncClient = ref object
c: AsyncSocket
mode: ClientMode
dataLen: int
headers: PStringTable ## the parsed headers
input: string ## the input buffer
TAsyncScgiState = object
handleRequest: proc (client: PAsyncSocket,
input: string, headers: PStringTable) {.closure,gcsafe.}
asyncServer: PAsyncSocket
disp: PDispatcher
PAsyncScgiState* = ref TAsyncScgiState
proc recvBuffer(s: var TScgiState, L: int) =
AsyncScgiStateObj = object
handleRequest: proc (client: AsyncSocket,
input: string,
headers: StringTableRef) {.closure, gcsafe.}
asyncServer: AsyncSocket
disp: Dispatcher
AsyncScgiState* = ref AsyncScgiStateObj
{.deprected: [EScgi: ScgiError, TScgiState: ScgiState,
PAsyncScgiState: AsyncScgiState, scgiError: raiseScgiError].}
proc recvBuffer(s: var ScgiState, L: int) =
if L > s.bufLen:
s.bufLen = L
s.input = newString(L)
if L > 0 and recv(s.client, cstring(s.input), L) != L:
scgiError("could not read all data")
raiseScgiError("could not read all data")
setLen(s.input, L)
proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1",
reuseAddr = False) =
proc open*(s: var ScgiState, port = Port(4000), address = "127.0.0.1",
reuseAddr = false) =
## opens a connection.
s.bufLen = 4000
s.input = newString(s.buflen) # will be reused
s.server = socket()
if s.server == InvalidSocket: osError(osLastError())
if s.server == InvalidSocket: raiseOSError(osLastError())
new(s.client) # Initialise s.client for `next`
if s.server == InvalidSocket: scgiError("could not open socket")
if s.server == InvalidSocket: raiseScgiError("could not open socket")
#s.server.connect(connectionName, port)
if reuseAddr:
s.server.setSockOpt(OptReuseAddr, True)
bindAddr(s.server, port, address)
listen(s.server)
proc close*(s: var TScgiState) =
proc close*(s: var ScgiState) =
## closes the connection.
s.server.close()
proc next*(s: var TScgistate, timeout: int = -1): bool =
proc next*(s: var ScgiState, timeout: int = -1): bool =
## proceed to the first/next request. Waits ``timeout`` miliseconds for a
## request, if ``timeout`` is `-1` then this function will never time out.
## Returns `True` if a new request has been processed.
## Returns `true` if a new request has been processed.
var rsocks = @[s.server]
if select(rsocks, timeout) == 1 and rsocks.len == 1:
new(s.client)
@ -132,17 +136,17 @@ proc next*(s: var TScgistate, timeout: int = -1): bool =
s.client.close()
return false
if d notin strutils.digits:
if d != ':': scgiError("':' after length expected")
if d != ':': raiseScgiError("':' after length expected")
break
L = L * 10 + ord(d) - ord('0')
recvBuffer(s, L+1)
s.headers = parseHeaders(s.input, L)
if s.headers["SCGI"] != "1": scgiError("SCGI Version 1 expected")
if s.headers["SCGI"] != "1": raiseScgiError("SCGI Version 1 expected")
L = parseInt(s.headers["CONTENT_LENGTH"])
recvBuffer(s, L)
return True
proc writeStatusOkTextContent*(c: TSocket, contentType = "text/html") =
proc writeStatusOkTextContent*(c: Socket, contentType = "text/html") =
## sends the following string to the socket `c`::
##
## Status: 200 OK\r\LContent-Type: text/html\r\L\r\L
@ -151,11 +155,11 @@ proc writeStatusOkTextContent*(c: TSocket, contentType = "text/html") =
c.send("Status: 200 OK\r\L" &
"Content-Type: $1\r\L\r\L" % contentType)
proc run*(handleRequest: proc (client: TSocket, input: string,
headers: PStringTable): bool {.nimcall,gcsafe.},
port = TPort(4000)) =
proc run*(handleRequest: proc (client: Socket, input: string,
headers: StringTableRef): bool {.nimcall,gcsafe.},
port = Port(4000)) =
## encapsulates the SCGI object and main loop.
var s: TScgiState
var s: ScgiState
s.open(port)
var stop = false
while not stop:
@ -166,11 +170,11 @@ proc run*(handleRequest: proc (client: TSocket, input: string,
# -- AsyncIO start
proc recvBufferAsync(client: PAsyncClient, L: int): TReadLineResult =
proc recvBufferAsync(client: AsyncClient, L: int): ReadLineResult =
result = ReadPartialLine
var data = ""
if L < 1:
scgiError("Cannot read negative or zero length: " & $L)
raiseScgiError("Cannot read negative or zero length: " & $L)
let ret = recvAsync(client.c, data, L)
if ret == 0 and data == "":
client.c.close()
@ -181,16 +185,16 @@ proc recvBufferAsync(client: PAsyncClient, L: int): TReadLineResult =
if ret == L:
return ReadFullLine
proc checkCloseSocket(client: PAsyncClient) =
proc checkCloseSocket(client: AsyncClient) =
if not client.c.isClosed:
if client.c.isSendDataBuffered:
client.c.setHandleWrite do (s: PAsyncSocket):
client.c.setHandleWrite do (s: AsyncSocket):
if not s.isClosed and not s.isSendDataBuffered:
s.close()
s.delHandleWrite()
else: client.c.close()
proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) =
proc handleClientRead(client: AsyncClient, s: AsyncScgiState) =
case client.mode
of ClientReadChar:
while true:
@ -203,7 +207,7 @@ proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) =
if ret == -1:
return # No more data available
if d[0] notin strutils.digits:
if d[0] != ':': scgiError("':' after length expected")
if d[0] != ':': raiseScgiError("':' after length expected")
break
client.dataLen = client.dataLen * 10 + ord(d[0]) - ord('0')
client.mode = ClientReadHeaders
@ -213,7 +217,7 @@ proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) =
case ret
of ReadFullLine:
client.headers = parseHeaders(client.input, client.input.len-1)
if client.headers["SCGI"] != "1": scgiError("SCGI Version 1 expected")
if client.headers["SCGI"] != "1": raiseScgiError("SCGI Version 1 expected")
client.input = "" # For next part
let contentLen = parseInt(client.headers["CONTENT_LENGTH"])
@ -236,50 +240,50 @@ proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) =
s.handleRequest(client.c, client.input, client.headers)
checkCloseSocket(client)
proc handleAccept(sock: PAsyncSocket, s: PAsyncScgiState) =
var client: PAsyncSocket
proc handleAccept(sock: AsyncSocket, s: AsyncScgiState) =
var client: AsyncSocket
new(client)
accept(s.asyncServer, client)
var asyncClient = PAsyncClient(c: client, mode: ClientReadChar, dataLen: 0,
var asyncClient = AsyncClient(c: client, mode: ClientReadChar, dataLen: 0,
headers: newStringTable(), input: "")
client.handleRead =
proc (sock: PAsyncSocket) =
proc (sock: AsyncSocket) =
handleClientRead(asyncClient, s)
s.disp.register(client)
proc open*(handleRequest: proc (client: PAsyncSocket,
input: string, headers: PStringTable) {.
proc open*(handleRequest: proc (client: AsyncSocket,
input: string, headers: StringTableRef) {.
closure, gcsafe.},
port = TPort(4000), address = "127.0.0.1",
reuseAddr = false): PAsyncScgiState =
## Creates an ``PAsyncScgiState`` object which serves as a SCGI server.
port = Port(4000), address = "127.0.0.1",
reuseAddr = false): AsyncScgiState =
## Creates an ``AsyncScgiState`` object which serves as a SCGI server.
##
## After the execution of ``handleRequest`` the client socket will be closed
## automatically unless it has already been closed.
var cres: PAsyncScgiState
var cres: AsyncScgiState
new(cres)
cres.asyncServer = AsyncSocket()
cres.asyncServer.handleAccept = proc (s: PAsyncSocket) = handleAccept(s, cres)
cres.asyncServer.handleAccept = proc (s: AsyncSocket) = handleAccept(s, cres)
if reuseAddr:
cres.asyncServer.setSockOpt(OptReuseAddr, True)
cres.asyncServer.setSockOpt(OptReuseAddr, true)
bindAddr(cres.asyncServer, port, address)
listen(cres.asyncServer)
cres.handleRequest = handleRequest
result = cres
proc register*(d: PDispatcher, s: PAsyncScgiState): PDelegate {.discardable.} =
proc register*(d: Dispatcher, s: AsyncScgiState): Delegate {.discardable.} =
## Registers ``s`` with dispatcher ``d``.
result = d.register(s.asyncServer)
s.disp = d
proc close*(s: PAsyncScgiState) =
## Closes the ``PAsyncScgiState``.
proc close*(s: AsyncScgiState) =
## Closes the ``AsyncScgiState``.
s.asyncServer.close()
when false:
var counter = 0
proc handleRequest(client: TSocket, input: string,
headers: PStringTable): bool {.procvar.} =
proc handleRequest(client: Socket, input: string,
headers: StringTableRef): bool {.procvar.} =
inc(counter)
client.writeStatusOkTextContent()
client.send("Hello for the $#th time." % $counter & "\c\L")

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -18,57 +18,57 @@ elif defined(windows):
else:
import posix
proc hash*(x: TSocketHandle): THash {.borrow.}
proc `$`*(x: TSocketHandle): string {.borrow.}
proc hash*(x: SocketHandle): THash {.borrow.}
proc `$`*(x: SocketHandle): string {.borrow.}
type
TEvent* = enum
Event* = enum
EvRead, EvWrite
PSelectorKey* = ref object
fd*: TSocketHandle
events*: set[TEvent] ## The events which ``fd`` listens for.
data*: PObject ## User object.
SelectorKey* = ref object
fd*: SocketHandle
events*: set[Event] ## The events which ``fd`` listens for.
data*: RootRef ## User object.
TReadyInfo* = tuple[key: PSelectorKey, events: set[TEvent]]
ReadyInfo* = tuple[key: SelectorKey, events: set[Event]]
when defined(nimdoc):
type
PSelector* = ref object
Selector* = ref object
## An object which holds file descripters to be checked for read/write
## status.
fds: TTable[TSocketHandle, PSelectorKey]
fds: Table[SocketHandle, SelectorKey]
proc register*(s: PSelector, fd: TSocketHandle, events: set[TEvent],
data: PObject): PSelectorKey {.discardable.} =
proc register*(s: Selector, fd: SocketHandle, events: set[Event],
data: RootRef): SelectorKey {.discardable.} =
## Registers file descriptor ``fd`` to selector ``s`` with a set of TEvent
## ``events``.
proc update*(s: PSelector, fd: TSocketHandle,
events: set[TEvent]): PSelectorKey {.discardable.} =
proc update*(s: Selector, fd: SocketHandle,
events: set[Event]): SelectorKey {.discardable.} =
## Updates the events which ``fd`` wants notifications for.
proc select*(s: PSelector, timeout: int): seq[TReadyInfo] =
proc select*(s: Selector, timeout: int): seq[ReadyInfo] =
## The ``events`` field of the returned ``key`` contains the original events
## for which the ``fd`` was bound. This is contrary to the ``events`` field
## of the ``TReadyInfo`` tuple which determines which events are ready
## on the ``fd``.
proc contains*(s: PSelector, fd: TSocketHandle): bool =
proc contains*(s: Selector, fd: SocketHandle): bool =
## Determines whether selector contains a file descriptor.
proc `[]`*(s: PSelector, fd: TSocketHandle): PSelectorKey =
proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
## Retrieves the selector key for ``fd``.
elif defined(linux):
type
PSelector* = ref object
Selector* = ref object
epollFD: cint
events: array[64, epoll_event]
fds: TTable[TSocketHandle, PSelectorKey]
fds: Table[SocketHandle, SelectorKey]
proc createEventStruct(events: set[TEvent], fd: TSocketHandle): epoll_event =
proc createEventStruct(events: set[Event], fd: SocketHandle): epoll_event =
if EvRead in events:
result.events = EPOLLIN
if EvWrite in events:
@ -76,22 +76,22 @@ elif defined(linux):
result.events = result.events or EPOLLRDHUP
result.data.fd = fd.cint
proc register*(s: PSelector, fd: TSocketHandle, events: set[TEvent],
data: PObject): PSelectorKey {.discardable.} =
proc register*(s: Selector, fd: SocketHandle, events: set[Event],
data: RootRef): SelectorKey {.discardable.} =
## Registers file descriptor ``fd`` to selector ``s`` with a set of TEvent
## ``events``.
var event = createEventStruct(events, fd)
if events != {}:
if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
OSError(OSLastError())
raiseOSError(osLastError())
var key = PSelectorKey(fd: fd, events: events, data: data)
var key = SelectorKey(fd: fd, events: events, data: data)
s.fds[fd] = key
result = key
proc update*(s: PSelector, fd: TSocketHandle,
events: set[TEvent]): PSelectorKey {.discardable.} =
proc update*(s: Selector, fd: SocketHandle,
events: set[Event]): SelectorKey {.discardable.} =
## Updates the events which ``fd`` wants notifications for.
if s.fds[fd].events != events:
if events == {}:
@ -101,7 +101,7 @@ elif defined(linux):
# because its got fds which are waiting for no events and
# are therefore constantly ready. (leading to 100% CPU usage).
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0:
OSError(OSLastError())
raiseOSError(osLastError())
s.fds[fd].events = events
else:
var event = createEventStruct(events, fd)
@ -109,36 +109,36 @@ elif defined(linux):
# This fd is idle. It's not a member of this epoll instance and must
# be re-registered.
if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
OSError(OSLastError())
raiseOSError(osLastError())
else:
if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0:
OSError(OSLastError())
raiseOSError(osLastError())
s.fds[fd].events = events
result = s.fds[fd]
proc unregister*(s: PSelector, fd: TSocketHandle): PSelectorKey {.discardable.} =
proc unregister*(s: Selector, fd: SocketHandle): SelectorKey {.discardable.} =
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0:
let err = OSLastError()
let err = osLastError()
if err.cint notin {ENOENT, EBADF}: # TODO: Why do we sometimes get an EBADF? Is this normal?
OSError(err)
raiseOSError(err)
result = s.fds[fd]
s.fds.del(fd)
proc close*(s: PSelector) =
if s.epollFD.close() != 0: OSError(OSLastError())
proc close*(s: Selector) =
if s.epollFD.close() != 0: raiseOSError(osLastError())
dealloc(addr s.events) # TODO: Test this
proc epollHasFd(s: PSelector, fd: TSocketHandle): bool =
proc epollHasFd(s: Selector, fd: SocketHandle): bool =
result = true
var event = createEventStruct(s.fds[fd].events, fd)
if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0:
let err = osLastError()
if err.cint in {ENOENT, EBADF}:
return false
OSError(OSLastError())
raiseOSError(osLastError())
proc select*(s: PSelector, timeout: int): seq[TReadyInfo] =
proc select*(s: Selector, timeout: int): seq[ReadyInfo] =
##
## The ``events`` field of the returned ``key`` contains the original events
## for which the ``fd`` was bound. This is contrary to the ``events`` field
@ -146,12 +146,12 @@ elif defined(linux):
## on the ``fd``.
result = @[]
let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint)
if evNum < 0: OSError(OSLastError())
if evNum < 0: raiseOSError(osLastError())
if evNum == 0: return @[]
for i in 0 .. <evNum:
let fd = s.events[i].data.fd.TSocketHandle
let fd = s.events[i].data.fd.SocketHandle
var evSet: set[TEvent] = {}
var evSet: set[Event] = {}
if (s.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead}
if (s.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite}
let selectorKey = s.fds[fd]
@ -160,15 +160,15 @@ elif defined(linux):
#echo("Epoll: ", result[i].key.fd, " ", result[i].events, " ", result[i].key.events)
proc newSelector*(): PSelector =
proc newSelector*(): Selector =
new result
result.epollFD = epoll_create(64)
#result.events = cast[array[64, epoll_event]](alloc0(sizeof(epoll_event)*64))
result.fds = initTable[TSocketHandle, PSelectorKey]()
result.fds = initTable[SocketHandle, SelectorKey]()
if result.epollFD < 0:
OSError(OSLastError())
raiseOSError(osLastError())
proc contains*(s: PSelector, fd: TSocketHandle): bool =
proc contains*(s: Selector, fd: SocketHandle): bool =
## Determines whether selector contains a file descriptor.
if s.fds.hasKey(fd):
# Ensure the underlying epoll instance still contains this fd.
@ -179,46 +179,46 @@ elif defined(linux):
else:
return false
proc `[]`*(s: PSelector, fd: TSocketHandle): PSelectorKey =
proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
## Retrieves the selector key for ``fd``.
return s.fds[fd]
elif not defined(nimdoc):
# TODO: kqueue for bsd/mac os x.
type
PSelector* = ref object
fds: TTable[TSocketHandle, PSelectorKey]
Selector* = ref object
fds: Table[SocketHandle, SelectorKey]
proc register*(s: PSelector, fd: TSocketHandle, events: set[TEvent],
data: PObject): PSelectorKey {.discardable.} =
proc register*(s: Selector, fd: SocketHandle, events: set[Event],
data: RootRef): SelectorKey {.discardable.} =
if s.fds.hasKey(fd):
raise newException(EInvalidValue, "File descriptor already exists.")
var sk = PSelectorKey(fd: fd, events: events, data: data)
raise newException(ValueError, "File descriptor already exists.")
var sk = SelectorKey(fd: fd, events: events, data: data)
s.fds[fd] = sk
result = sk
proc update*(s: PSelector, fd: TSocketHandle,
events: set[TEvent]): PSelectorKey {.discardable.} =
proc update*(s: Selector, fd: SocketHandle,
events: set[Event]): SelectorKey {.discardable.} =
## Updates the events which ``fd`` wants notifications for.
if not s.fds.hasKey(fd):
raise newException(EInvalidValue, "File descriptor not found.")
raise newException(ValueError, "File descriptor not found.")
s.fds[fd].events = events
result = s.fds[fd]
proc unregister*(s: PSelector, fd: TSocketHandle): PSelectorKey {.discardable.} =
proc unregister*(s: Selector, fd: SocketHandle): SelectorKey {.discardable.} =
result = s.fds[fd]
s.fds.del(fd)
proc close*(s: PSelector) = nil
proc close*(s: Selector) = discard
proc timeValFromMilliseconds(timeout: int): TTimeVal =
proc timeValFromMilliseconds(timeout: int): TimeVal =
if timeout != -1:
var seconds = timeout div 1000
result.tv_sec = seconds.int32
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
proc createFdSet(rd, wr: var TFdSet, fds: TTable[TSocketHandle, PSelectorKey],
proc createFdSet(rd, wr: var FdSet, fds: Table[SocketHandle, SelectorKey],
m: var int) =
FD_ZERO(rd); FD_ZERO(wr)
for k, v in pairs(fds):
@ -229,22 +229,22 @@ elif not defined(nimdoc):
m = max(m, int(k))
FD_SET(k, wr)
proc getReadyFDs(rd, wr: var TFdSet, fds: TTable[TSocketHandle, PSelectorKey]):
seq[TReadyInfo] =
proc getReadyFDs(rd, wr: var FdSet, fds: Table[SocketHandle, SelectorKey]):
seq[ReadyInfo] =
result = @[]
for k, v in pairs(fds):
var events: set[TEvent] = {}
var events: set[Event] = {}
if FD_ISSET(k, rd) != 0'i32:
events = events + {EvRead}
if FD_ISSET(k, wr) != 0'i32:
events = events + {EvWrite}
result.add((v, events))
proc select(fds: TTable[TSocketHandle, PSelectorKey], timeout = 500):
seq[TReadyInfo] =
var tv {.noInit.}: TTimeVal = timeValFromMilliseconds(timeout)
proc select(fds: Table[SocketHandle, SelectorKey], timeout = 500):
seq[ReadyInfo] =
var tv {.noInit.}: TimeVal = timeValFromMilliseconds(timeout)
var rd, wr: TFdSet
var rd, wr: FdSet
var m = 0
createFdSet(rd, wr, fds, m)
@ -255,26 +255,26 @@ elif not defined(nimdoc):
retCode = int(select(cint(m+1), addr(rd), addr(wr), nil, nil))
if retCode < 0:
OSError(OSLastError())
raiseOSError(osLastError())
elif retCode == 0:
return @[]
else:
return getReadyFDs(rd, wr, fds)
proc select*(s: PSelector, timeout: int): seq[TReadyInfo] =
proc select*(s: Selector, timeout: int): seq[ReadyInfo] =
result = select(s.fds, timeout)
proc newSelector*(): PSelector =
proc newSelector*(): Selector =
new result
result.fds = initTable[TSocketHandle, PSelectorKey]()
result.fds = initTable[SocketHandle, SelectorKey]()
proc contains*(s: PSelector, fd: TSocketHandle): bool =
proc contains*(s: Selector, fd: SocketHandle): bool =
return s.fds.hasKey(fd)
proc `[]`*(s: PSelector, fd: TSocketHandle): PSelectorKey =
proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
return s.fds[fd]
proc contains*(s: PSelector, key: PSelectorKey): bool =
proc contains*(s: Selector, key: SelectorKey): bool =
## Determines whether selector contains this selector key. More accurate
## than checking if the file descriptor is in the selector because it
## ensures that the keys are equal. File descriptors may not always be
@ -282,20 +282,24 @@ proc contains*(s: PSelector, key: PSelectorKey): bool =
## the new one may have the same value.
return key.fd in s and s.fds[key.fd] == key
{.deprecated: [TEvent: Event, PSelectorKey: SelectorKey,
TReadyInfo: ReadyInfo, PSelector: Selector].}
when isMainModule and not defined(nimdoc):
# Select()
import sockets
type
PSockWrapper = ref object of PObject
sock: TSocket
SockWrapper = ref object of RootObj
sock: Socket
var sock = socket()
if sock == sockets.InvalidSocket: osError(osLastError())
if sock == sockets.InvalidSocket: raiseOSError(osLastError())
#sock.setBlocking(false)
sock.connect("irc.freenode.net", TPort(6667))
sock.connect("irc.freenode.net", Port(6667))
var selector = newSelector()
var data = PSockWrapper(sock: sock)
var data = SockWrapper(sock: sock)
let key = selector.register(sock.getFD, {EvWrite}, data)
var i = 0
while true:

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -16,11 +16,11 @@
## Example gmail use:
##
##
## .. code-block:: Nimrod
## var msg = createMessage("Hello from Nimrod's SMTP",
## .. code-block:: Nim
## var msg = createMessage("Hello from Nim's SMTP",
## "Hello!.\n Is this awesome or what?",
## @["foo@gmail.com"])
## var smtp = connect("smtp.gmail.com", 465, True, True)
## var smtp = connect("smtp.gmail.com", 465, true, true)
## smtp.auth("username", "password")
## smtp.sendmail("username@gmail.com", @["foo@gmail.com"], $msg)
##
@ -31,18 +31,20 @@
import sockets, strutils, strtabs, base64, os
type
TSMTP* {.final.} = object
sock: TSocket
debug: Bool
Smtp* = object
sock: Socket
debug: bool
TMessage* {.final.} = object
Message* = object
msgTo: seq[string]
msgCc: seq[string]
msgSubject: string
msgOtherHeaders: PStringTable
msgOtherHeaders: StringTableRef
msgBody: string
EInvalidReply* = object of EIO
ReplyError* = object of IOError
{.deprecated: [EInvalidReply: ReplyError, TMessage: Message, TSMTP: Smtp].}
proc debugSend(smtp: TSMTP, cmd: string) =
if smtp.debug:
@ -170,7 +172,7 @@ when isMainModule:
#smtp.sendmail("root@localhost", @["dominik@localhost"], $msg)
#echo(decode("a17sm3701420wbe.12"))
var msg = createMessage("Hello from Nimrod's SMTP!",
var msg = createMessage("Hello from Nim's SMTP!",
"Hello!!!!.\n Is this awesome or what?",
@["someone@yahoo.com", "someone@gmail.com"])
echo(msg)

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2013 Andreas Rumpf, Dominik Picheta
#
# See the file "copying.txt", included in this
@ -14,8 +14,8 @@
## the ``socket`` function to `false`. Be aware that some functions may not yet
## support buffered sockets (mainly the recvFrom function).
##
## Most procedures raise EOS on error, but some may return ``-1`` or a boolean
## ``false``.
## Most procedures raise OSError on error, but some may return ``-1`` or a
## boolean ``false``.
##
## SSL is supported through the OpenSSL library. This support can be activated
## by compiling with the ``-d:ssl`` switch. When an SSL socket is used it will
@ -47,25 +47,29 @@ else:
when defined(ssl):
type
ESSL* = object of ESynch
SSLError* = object of Exception
TSSLCVerifyMode* = enum
SSLCVerifyMode* = enum
CVerifyNone, CVerifyPeer
TSSLProtVersion* = enum
SSLProtVersion* = enum
protSSLv2, protSSLv3, protTLSv1, protSSLv23
PSSLContext* = distinct PSSLCTX
SSLContext* = distinct PSSLCTX
TSSLAcceptResult* = enum
SSLAcceptResult* = enum
AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess
{.deprecated: [ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode,
TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext,
TSSLAcceptResult: SSLAcceptResult].}
const
BufferSize*: int = 4000 ## size of a buffered socket's buffer
type
TSocketImpl = object ## socket type
fd: TSocketHandle
fd: SocketHandle
case isBuffered: bool # determines whether this socket is buffered.
of true:
buffer: array[0..BufferSize, char]
@ -76,31 +80,31 @@ type
case isSsl: bool
of true:
sslHandle: PSSL
sslContext: PSSLContext
sslContext: SSLContext
sslNoHandshake: bool # True if needs handshake.
sslHasPeekChar: bool
sslPeekChar: char
of false: nil
nonblocking: bool
TSocket* = ref TSocketImpl
Socket* = ref TSocketImpl
TPort* = distinct uint16 ## port type
Port* = distinct uint16 ## port type
TDomain* = enum ## domain, which specifies the protocol family of the
Domain* = enum ## domain, which specifies the protocol family of the
## created socket. Other domains than those that are listed
## here are unsupported.
AF_UNIX, ## for local socket (using a file). Unsupported on Windows.
AF_INET = 2, ## for network protocol IPv4 or
AF_INET6 = 23 ## for network protocol IPv6.
TType* = enum ## second argument to `socket` proc
SockType* = enum ## second argument to `socket` proc
SOCK_STREAM = 1, ## reliable stream-oriented service or Stream Sockets
SOCK_DGRAM = 2, ## datagram service or Datagram Sockets
SOCK_RAW = 3, ## raw protocols atop the network layer.
SOCK_SEQPACKET = 5 ## reliable sequenced packet service
TProtocol* = enum ## third argument to `socket` proc
Protocol* = enum ## third argument to `socket` proc
IPPROTO_TCP = 6, ## Transmission control protocol.
IPPROTO_UDP = 17, ## User datagram protocol.
IPPROTO_IP, ## Internet protocol. Unsupported on Windows.
@ -108,33 +112,39 @@ type
IPPROTO_RAW, ## Raw IP Packets Protocol. Unsupported on Windows.
IPPROTO_ICMP ## Control message protocol. Unsupported on Windows.
TServent* {.pure, final.} = object ## information about a service
Servent* = object ## information about a service
name*: string
aliases*: seq[string]
port*: TPort
port*: Port
proto*: string
Thostent* {.pure, final.} = object ## information about a given host
Hostent* = object ## information about a given host
name*: string
aliases*: seq[string]
addrtype*: TDomain
addrtype*: Domain
length*: int
addrList*: seq[string]
TSOBool* = enum ## Boolean socket options.
SOBool* = enum ## Boolean socket options.
OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
OptOOBInline, OptReuseAddr
TRecvLineResult* = enum ## result for recvLineAsync
RecvLineResult* = enum ## result for recvLineAsync
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
TReadLineResult* = enum ## result for readLineAsync
ReadLineResult* = enum ## result for readLineAsync
ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone
ETimeout* = object of Exception
TimeoutError* = object of Exception
{.deprecated: [TSocket: Socket, TType: SockType, TPort: Port, TDomain: Domain,
TProtocol: Protocol, TServent: Servent, THostent: Hostent,
TSOBool: SOBool, TRecvLineResult: RecvLineResult,
TReadLineResult: ReadLineResult, ETimeout: TimeoutError].}
let
invalidSocket*: TSocket = nil ## invalid socket
invalidSocket*: Socket = nil ## invalid socket
when defined(windows):
let
@ -143,7 +153,7 @@ else:
let
osInvalidSocket = posix.INVALID_SOCKET
proc newTSocket(fd: TSocketHandle, isBuff: bool): TSocket =
proc newTSocket(fd: SocketHandle, isBuff: bool): Socket =
if fd == osInvalidSocket:
return nil
new(result)
@ -153,10 +163,10 @@ proc newTSocket(fd: TSocketHandle, isBuff: bool): TSocket =
result.currPos = 0
result.nonblocking = false
proc `==`*(a, b: TPort): bool {.borrow.}
proc `==`*(a, b: Port): bool {.borrow.}
## ``==`` for ports.
proc `$`*(p: TPort): string {.borrow.}
proc `$`*(p: Port): string {.borrow.}
## returns the port number as a string
proc ntohl*(x: int32): int32 =
@ -189,14 +199,14 @@ proc htons*(x: int16): int16 =
result = sockets.ntohs(x)
when defined(Posix):
proc toInt(domain: TDomain): cint =
proc toInt(domain: Domain): cint =
case domain
of AF_UNIX: result = posix.AF_UNIX
of AF_INET: result = posix.AF_INET
of AF_INET6: result = posix.AF_INET6
else: discard
proc toInt(typ: TType): cint =
proc toInt(typ: SockType): cint =
case typ
of SOCK_STREAM: result = posix.SOCK_STREAM
of SOCK_DGRAM: result = posix.SOCK_DGRAM
@ -204,7 +214,7 @@ when defined(Posix):
of SOCK_RAW: result = posix.SOCK_RAW
else: discard
proc toInt(p: TProtocol): cint =
proc toInt(p: Protocol): cint =
case p
of IPPROTO_TCP: result = posix.IPPROTO_TCP
of IPPROTO_UDP: result = posix.IPPROTO_UDP
@ -215,13 +225,13 @@ when defined(Posix):
else: discard
else:
proc toInt(domain: TDomain): cint =
proc toInt(domain: Domain): cint =
result = toU16(ord(domain))
proc toInt(typ: TType): cint =
proc toInt(typ: SockType): cint =
result = cint(ord(typ))
proc toInt(p: TProtocol): cint =
proc toInt(p: Protocol): cint =
result = cint(ord(p))
proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
@ -336,7 +346,7 @@ when defined(ssl):
if SSLSetFd(socket.sslHandle, socket.fd) != 1:
SSLError()
proc socketError*(socket: TSocket, err: int = -1, async = false) =
proc raiseSocketError*(socket: TSocket, err: int = -1, async = false) =
## Raises proper errors based on return values of ``recv`` functions.
##
## If ``async`` is ``True`` no error will be thrown in the case when the
@ -370,18 +380,18 @@ proc socketError*(socket: TSocket, err: int = -1, async = false) =
when defined(windows):
if lastError.int32 == WSAEWOULDBLOCK:
return
else: osError(lastError)
else: raiseOSError(lastError)
else:
if lastError.int32 == EAGAIN or lastError.int32 == EWOULDBLOCK:
return
else: osError(lastError)
else: osError(lastError)
else: raiseOSError(lastError)
else: raiseOSError(lastError)
proc listen*(socket: TSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
## Marks ``socket`` as accepting connections.
## ``Backlog`` specifies the maximum length of the
## queue of pending connections.
if listen(socket.fd, cint(backlog)) < 0'i32: osError(osLastError())
if listen(socket.fd, cint(backlog)) < 0'i32: raiseOSError(osLastError())
proc invalidIp4(s: string) {.noreturn, noinline.} =
raise newException(ValueError, "invalid ip4 address: " & s)
@ -420,7 +430,7 @@ template gaiNim(a, p, h, list: expr): stmt =
var gaiResult = getaddrinfo(a, $p, addr(h), list)
if gaiResult != 0'i32:
when defined(windows):
osError(osLastError())
raiseOSError(osLastError())
else:
raise newException(OSError, $gai_strerror(gaiResult))
@ -440,7 +450,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
if bindSocket(socket.fd, cast[ptr TSockAddr](addr(name)),
sizeof(name).TSocklen) < 0'i32:
osError(osLastError())
raiseOSError(osLastError())
else:
var hints: Taddrinfo
var aiList: ptr Taddrinfo = nil
@ -449,7 +459,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
hints.ai_protocol = toInt(IPPROTO_TCP)
gaiNim(address, port, hints, aiList)
if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrlen.TSocklen) < 0'i32:
osError(osLastError())
raiseOSError(osLastError())
proc getSockName*(socket: TSocket): TPort =
## returns the socket's associated port number.
@ -463,7 +473,7 @@ proc getSockName*(socket: TSocket): TPort =
var namelen = sizeof(name).TSocklen
if getsockname(socket.fd, cast[ptr TSockAddr](addr(name)),
addr(namelen)) == -1'i32:
osError(osLastError())
raiseOSError(osLastError())
result = TPort(sockets.ntohs(name.sin_port))
template acceptAddrPlain(noClientRet, successRet: expr,
@ -484,7 +494,7 @@ template acceptAddrPlain(noClientRet, successRet: expr,
return
else:
return noClientRet
else: osError(err)
else: raiseOSError(err)
else:
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
client = invalidSocket
@ -493,7 +503,7 @@ template acceptAddrPlain(noClientRet, successRet: expr,
return
else:
return noClientRet
else: osError(err)
else: raiseOSError(err)
else:
client.fd = sock
client.isBuffered = server.isBuffered
@ -680,7 +690,7 @@ proc getHostByAddr*(ip: string): Thostent {.tags: [ReadIOEffect].} =
when defined(windows):
var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
cint(sockets.AF_INET))
if s == nil: osError(osLastError())
if s == nil: raiseOSError(osLastError())
else:
var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSocklen,
cint(posix.AF_INET))
@ -707,7 +717,7 @@ proc getHostByName*(name: string): Thostent {.tags: [ReadIOEffect].} =
var s = winlean.gethostbyname(name)
else:
var s = posix.gethostbyname(name)
if s == nil: osError(osLastError())
if s == nil: raiseOSError(osLastError())
result.name = $s.h_name
result.aliases = cstringArrayToSeq(s.h_aliases)
when defined(windows):
@ -729,7 +739,7 @@ proc getSockOptInt*(socket: TSocket, level, optname: int): int {.
var size = sizeof(res).TSocklen
if getsockopt(socket.fd, cint(level), cint(optname),
addr(res), addr(size)) < 0'i32:
osError(osLastError())
raiseOSError(osLastError())
result = int(res)
proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
@ -738,7 +748,7 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
var value = cint(optval)
if setsockopt(socket.fd, cint(level), cint(optname), addr(value),
sizeof(value).TSocklen) < 0'i32:
osError(osLastError())
raiseOSError(osLastError())
proc toCInt(opt: TSOBool): cint =
case opt
@ -757,7 +767,7 @@ proc getSockOpt*(socket: TSocket, opt: TSOBool, level = SOL_SOCKET): bool {.
var size = sizeof(res).TSocklen
if getsockopt(socket.fd, cint(level), toCInt(opt),
addr(res), addr(size)) < 0'i32:
osError(osLastError())
raiseOSError(osLastError())
result = res != 0
proc setSockOpt*(socket: TSocket, opt: TSOBool, value: bool, level = SOL_SOCKET) {.
@ -766,7 +776,7 @@ proc setSockOpt*(socket: TSocket, opt: TSOBool, value: bool, level = SOL_SOCKET)
var valuei = cint(if value: 1 else: 0)
if setsockopt(socket.fd, cint(level), toCInt(opt), addr(valuei),
sizeof(valuei).TSocklen) < 0'i32:
osError(osLastError())
raiseOSError(osLastError())
proc connect*(socket: TSocket, address: string, port = TPort(0),
af: TDomain = AF_INET) {.tags: [ReadIOEffect].} =
@ -784,7 +794,7 @@ proc connect*(socket: TSocket, address: string, port = TPort(0),
gaiNim(address, port, hints, aiList)
# try all possibilities:
var success = false
var lastError: TOSErrorCode
var lastError: OSErrorCode
var it = aiList
while it != nil:
if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen) == 0'i32:
@ -794,7 +804,7 @@ proc connect*(socket: TSocket, address: string, port = TPort(0),
it = it.ai_next
freeaddrinfo(aiList)
if not success: osError(lastError)
if not success: raiseOSError(lastError)
when defined(ssl):
if socket.isSSL:
@ -847,7 +857,7 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
gaiNim(name, port, hints, aiList)
# try all possibilities:
var success = false
var lastError: TOSErrorCode
var lastError: OSErrorCode
var it = aiList
while it != nil:
var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen)
@ -869,7 +879,7 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
it = it.ai_next
freeaddrinfo(aiList)
if not success: osError(lastError)
if not success: raiseOSError(lastError)
when defined(ssl):
if socket.isSSL:
socket.sslNoHandshake = true
@ -1133,7 +1143,7 @@ proc waitFor(socket: TSocket, waited: var float, timeout, size: int,
result = min(result, size)
else:
if timeout - int(waited * 1000.0) < 1:
raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
when defined(ssl):
if socket.isSSL:
@ -1147,9 +1157,9 @@ proc waitFor(socket: TSocket, waited: var float, timeout, size: int,
var s = @[socket]
var startTime = epochTime()
let selRet = select(s, timeout - int(waited * 1000.0))
if selRet < 0: osError(osLastError())
if selRet < 0: raiseOSError(osLastError())
if selRet != 1:
raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
waited += (epochTime() - startTime)
proc recv*(socket: TSocket, data: pointer, size: int, timeout: int): int {.
@ -1185,7 +1195,7 @@ proc recv*(socket: TSocket, data: var string, size: int, timeout = -1): int =
result = recv(socket, cstring(data), size, timeout)
if result < 0:
data.setLen(0)
socket.socketError(result)
socket.raiseSocketError(result)
data.setLen(result)
proc recvAsync*(socket: TSocket, data: var string, size: int): int =
@ -1199,7 +1209,7 @@ proc recvAsync*(socket: TSocket, data: var string, size: int): int =
result = recv(socket, cstring(data), size)
if result < 0:
data.setLen(0)
socket.socketError(async = true)
socket.raiseSocketError(async = true)
result = -1
data.setLen(result)
@ -1296,14 +1306,14 @@ proc readLine*(socket: TSocket, line: var TaintedString, timeout = -1) {.
var c: char
discard waitFor(socket, waited, timeout, 1, "readLine")
var n = recv(socket, addr(c), 1)
if n < 0: socket.socketError()
if n < 0: socket.raiseSocketError()
elif n == 0: return
if c == '\r':
discard waitFor(socket, waited, timeout, 1, "readLine")
n = peekChar(socket, c)
if n > 0 and c == '\L':
discard recv(socket, addr(c), 1)
elif n <= 0: socket.socketError()
elif n <= 0: socket.raiseSocketError()
addNLIfEmpty()
return
elif c == '\L':
@ -1357,7 +1367,7 @@ proc readLineAsync*(socket: TSocket,
setLen(line.string, 0)
template errorOrNone =
socket.socketError(async = true)
socket.raiseSocketError(async = true)
return ReadNone
while true:
@ -1390,7 +1400,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [ReadIOEffect], deprecated.}
var pos = 0
while true:
var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1)
if bytesRead == -1: osError(osLastError())
if bytesRead == -1: raiseOSError(osLastError())
setLen(result.string, pos + bytesRead)
if bytesRead != bufSize-1: break
# increase capacity:
@ -1463,11 +1473,11 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool {.
when defined(windows):
if err.int32 == WSAEWOULDBLOCK:
return false
else: osError(err)
else: raiseOSError(err)
else:
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
return false
else: osError(err)
else: raiseOSError(err)
setLen(s.string, pos + bytesRead)
if bytesRead != bufSize-1: break
@ -1516,11 +1526,11 @@ proc recvFromAsync*(socket: TSocket, data: var string, length: int,
when defined(windows):
if err.int32 == WSAEWOULDBLOCK:
return false
else: osError(err)
else: raiseOSError(err)
else:
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
return false
else: osError(err)
else: raiseOSError(err)
proc skip*(socket: TSocket) {.tags: [ReadIOEffect], deprecated.} =
## skips all the data that is pending for the socket
@ -1570,7 +1580,7 @@ proc send*(socket: TSocket, data: string) {.tags: [WriteIOEffect].} =
if socket.isSSL:
SSLError()
osError(osLastError())
raiseOSError(osLastError())
if sent != data.len:
raise newException(OSError, "Could not send all data.")
@ -1607,11 +1617,11 @@ proc sendAsync*(socket: TSocket, data: string): int {.tags: [WriteIOEffect].} =
when defined(windows):
if err.int32 == WSAEINPROGRESS:
return 0
else: osError(err)
else: raiseOSError(err)
else:
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
return 0
else: osError(err)
else: raiseOSError(err)
proc trySend*(socket: TSocket, data: string): bool {.tags: [WriteIOEffect].} =
@ -1667,15 +1677,15 @@ proc setBlocking(s: TSocket, blocking: bool) =
when defined(Windows):
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
if ioctlsocket(s.fd, FIONBIO, addr(mode)) == -1:
osError(osLastError())
raiseOSError(osLastError())
else: # BSD sockets
var x: int = fcntl(s.fd, F_GETFL, 0)
if x == -1:
osError(osLastError())
raiseOSError(osLastError())
else:
var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
if fcntl(s.fd, F_SETFL, mode) == -1:
osError(osLastError())
raiseOSError(osLastError())
s.nonblocking = not blocking
discard """ proc setReuseAddr*(s: TSocket) =
@ -1715,6 +1725,6 @@ proc isBlocking*(socket: TSocket): bool = not socket.nonblocking
when defined(Windows):
var wsa: TWSAData
if wsaStartup(0x0101'i16, addr wsa) != 0: osError(osLastError())
if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError())

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -8,8 +8,8 @@
#
## This module provides a stream interface and two implementations thereof:
## the `PFileStream` and the `PStringStream` which implement the stream
## interface for Nimrod file objects (`TFile`) and strings. Other modules
## the `FileStream` and the `StringStream` which implement the stream
## interface for Nimrod file objects (`File`) and strings. Other modules
## may provide other implementations for this standard stream interface.
include "system/inclrtl"
@ -19,81 +19,83 @@ proc newEIO(msg: string): ref IOError =
result.msg = msg
type
PStream* = ref TStream
TStream* = object of RootObj ## Stream interface that supports
## writing or reading. Note that these fields
## here shouldn't be used directly. They are
## accessible so that a stream implementation
## can override them.
closeImpl*: proc (s: PStream) {.nimcall, tags: [], gcsafe.}
atEndImpl*: proc (s: PStream): bool {.nimcall, tags: [], gcsafe.}
setPositionImpl*: proc (s: PStream, pos: int) {.nimcall, tags: [], gcsafe.}
getPositionImpl*: proc (s: PStream): int {.nimcall, tags: [], gcsafe.}
readDataImpl*: proc (s: PStream, buffer: pointer,
Stream* = ref StreamObj
StreamObj* = object of RootObj ## Stream interface that supports
## writing or reading. Note that these fields
## here shouldn't be used directly. They are
## accessible so that a stream implementation
## can override them.
closeImpl*: proc (s: Stream) {.nimcall, tags: [], gcsafe.}
atEndImpl*: proc (s: Stream): bool {.nimcall, tags: [], gcsafe.}
setPositionImpl*: proc (s: Stream, pos: int) {.nimcall, tags: [], gcsafe.}
getPositionImpl*: proc (s: Stream): int {.nimcall, tags: [], gcsafe.}
readDataImpl*: proc (s: Stream, buffer: pointer,
bufLen: int): int {.nimcall, tags: [ReadIOEffect], gcsafe.}
writeDataImpl*: proc (s: PStream, buffer: pointer, bufLen: int) {.nimcall,
writeDataImpl*: proc (s: Stream, buffer: pointer, bufLen: int) {.nimcall,
tags: [WriteIOEffect], gcsafe.}
flushImpl*: proc (s: PStream) {.nimcall, tags: [WriteIOEffect], gcsafe.}
flushImpl*: proc (s: Stream) {.nimcall, tags: [WriteIOEffect], gcsafe.}
proc flush*(s: PStream) =
{.deprecated: [PStream: Stream, TStream: StreamObj].}
proc flush*(s: Stream) =
## flushes the buffers that the stream `s` might use.
if not isNil(s.flushImpl): s.flushImpl(s)
proc close*(s: PStream) =
proc close*(s: Stream) =
## closes the stream `s`.
if not isNil(s.closeImpl): s.closeImpl(s)
proc close*(s, unused: PStream) {.deprecated.} =
proc close*(s, unused: Stream) {.deprecated.} =
## closes the stream `s`.
s.closeImpl(s)
proc atEnd*(s: PStream): bool =
proc atEnd*(s: Stream): bool =
## checks if more data can be read from `f`. Returns true if all data has
## been read.
result = s.atEndImpl(s)
proc atEnd*(s, unused: PStream): bool {.deprecated.} =
proc atEnd*(s, unused: Stream): bool {.deprecated.} =
## checks if more data can be read from `f`. Returns true if all data has
## been read.
result = s.atEndImpl(s)
proc setPosition*(s: PStream, pos: int) =
proc setPosition*(s: Stream, pos: int) =
## sets the position `pos` of the stream `s`.
s.setPositionImpl(s, pos)
proc setPosition*(s, unused: PStream, pos: int) {.deprecated.} =
proc setPosition*(s, unused: Stream, pos: int) {.deprecated.} =
## sets the position `pos` of the stream `s`.
s.setPositionImpl(s, pos)
proc getPosition*(s: PStream): int =
proc getPosition*(s: Stream): int =
## retrieves the current position in the stream `s`.
result = s.getPositionImpl(s)
proc getPosition*(s, unused: PStream): int {.deprecated.} =
proc getPosition*(s, unused: Stream): int {.deprecated.} =
## retrieves the current position in the stream `s`.
result = s.getPositionImpl(s)
proc readData*(s: PStream, buffer: pointer, bufLen: int): int =
proc readData*(s: Stream, buffer: pointer, bufLen: int): int =
## low level proc that reads data into an untyped `buffer` of `bufLen` size.
result = s.readDataImpl(s, buffer, bufLen)
proc readData*(s, unused: PStream, buffer: pointer,
proc readData*(s, unused: Stream, buffer: pointer,
bufLen: int): int {.deprecated.} =
## low level proc that reads data into an untyped `buffer` of `bufLen` size.
result = s.readDataImpl(s, buffer, bufLen)
proc writeData*(s: PStream, buffer: pointer, bufLen: int) =
proc writeData*(s: Stream, buffer: pointer, bufLen: int) =
## low level proc that writes an untyped `buffer` of `bufLen` size
## to the stream `s`.
s.writeDataImpl(s, buffer, bufLen)
proc writeData*(s, unused: PStream, buffer: pointer,
proc writeData*(s, unused: Stream, buffer: pointer,
bufLen: int) {.deprecated.} =
## low level proc that writes an untyped `buffer` of `bufLen` size
## to the stream `s`.
s.writeDataImpl(s, buffer, bufLen)
proc write*[T](s: PStream, x: T) =
proc write*[T](s: Stream, x: T) =
## generic write procedure. Writes `x` to the stream `s`. Implementation:
##
## .. code-block:: Nimrod
@ -103,63 +105,63 @@ proc write*[T](s: PStream, x: T) =
shallowCopy(y, x)
writeData(s, addr(y), sizeof(y))
proc write*(s: PStream, x: string) =
proc write*(s: Stream, x: string) =
## writes the string `x` to the the stream `s`. No length field or
## terminating zero is written.
writeData(s, cstring(x), x.len)
proc writeln*(s: PStream, args: varargs[string, `$`]) =
proc writeln*(s: Stream, args: varargs[string, `$`]) =
## writes one or more strings to the the stream `s` followed
## by a new line. No length field or terminating zero is written.
for str in args: write(s, str)
write(s, "\n")
proc read[T](s: PStream, result: var T) =
proc read[T](s: Stream, result: var T) =
## generic read procedure. Reads `result` from the stream `s`.
if readData(s, addr(result), sizeof(T)) != sizeof(T):
raise newEIO("cannot read from stream")
proc readChar*(s: PStream): char =
proc readChar*(s: Stream): char =
## reads a char from the stream `s`. Raises `EIO` if an error occured.
## Returns '\0' as an EOF marker.
if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
proc readBool*(s: PStream): bool =
proc readBool*(s: Stream): bool =
## reads a bool from the stream `s`. Raises `EIO` if an error occured.
read(s, result)
proc readInt8*(s: PStream): int8 =
proc readInt8*(s: Stream): int8 =
## reads an int8 from the stream `s`. Raises `EIO` if an error occured.
read(s, result)
proc readInt16*(s: PStream): int16 =
proc readInt16*(s: Stream): int16 =
## reads an int16 from the stream `s`. Raises `EIO` if an error occured.
read(s, result)
proc readInt32*(s: PStream): int32 =
proc readInt32*(s: Stream): int32 =
## reads an int32 from the stream `s`. Raises `EIO` if an error occured.
read(s, result)
proc readInt64*(s: PStream): int64 =
proc readInt64*(s: Stream): int64 =
## reads an int64 from the stream `s`. Raises `EIO` if an error occured.
read(s, result)
proc readFloat32*(s: PStream): float32 =
proc readFloat32*(s: Stream): float32 =
## reads a float32 from the stream `s`. Raises `EIO` if an error occured.
read(s, result)
proc readFloat64*(s: PStream): float64 =
proc readFloat64*(s: Stream): float64 =
## reads a float64 from the stream `s`. Raises `EIO` if an error occured.
read(s, result)
proc readStr*(s: PStream, length: int): TaintedString =
proc readStr*(s: Stream, length: int): TaintedString =
## reads a string of length `length` from the stream `s`. Raises `EIO` if
## an error occured.
result = newString(length).TaintedString
var L = readData(s, addr(string(result)[0]), length)
if L != length: setLen(result.string, L)
proc readLine*(s: PStream, line: var TaintedString): bool =
proc readLine*(s: Stream, line: var TaintedString): bool =
## reads a line of text from the stream `s` into `line`. `line` must not be
## ``nil``! May throw an IO exception.
## A line of text may be delimited by ``CR``, ``LF`` or
@ -179,7 +181,7 @@ proc readLine*(s: PStream, line: var TaintedString): bool =
line.string.add(c)
result = true
proc readLine*(s: PStream): TaintedString =
proc readLine*(s: Stream): TaintedString =
## Reads a line from a stream `s`. Note: This is not very efficient. Raises
## `EIO` if an error occured.
result = TaintedString""
@ -194,42 +196,44 @@ proc readLine*(s: PStream): TaintedString =
result.string.add(c)
type
PStringStream* = ref TStringStream ## a stream that encapsulates a string
TStringStream* = object of TStream
StringStream* = ref StringStreamObj ## a stream that encapsulates a string
StringStreamObj* = object of StreamObj
data*: string
pos: int
proc ssAtEnd(s: PStream): bool =
var s = PStringStream(s)
{.deprecated: [PStringStream: StringStream, TStringStream: StringStreamObj].}
proc ssAtEnd(s: Stream): bool =
var s = StringStream(s)
return s.pos >= s.data.len
proc ssSetPosition(s: PStream, pos: int) =
var s = PStringStream(s)
proc ssSetPosition(s: Stream, pos: int) =
var s = StringStream(s)
s.pos = clamp(pos, 0, s.data.high)
proc ssGetPosition(s: PStream): int =
var s = PStringStream(s)
proc ssGetPosition(s: Stream): int =
var s = StringStream(s)
return s.pos
proc ssReadData(s: PStream, buffer: pointer, bufLen: int): int =
var s = PStringStream(s)
proc ssReadData(s: Stream, buffer: pointer, bufLen: int): int =
var s = StringStream(s)
result = min(bufLen, s.data.len - s.pos)
if result > 0:
copyMem(buffer, addr(s.data[s.pos]), result)
inc(s.pos, result)
proc ssWriteData(s: PStream, buffer: pointer, bufLen: int) =
var s = PStringStream(s)
proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) =
var s = StringStream(s)
if bufLen > 0:
setLen(s.data, s.data.len + bufLen)
copyMem(addr(s.data[s.pos]), buffer, bufLen)
inc(s.pos, bufLen)
proc ssClose(s: PStream) =
var s = PStringStream(s)
proc ssClose(s: Stream) =
var s = StringStream(s)
s.data = nil
proc newStringStream*(s: string = ""): PStringStream =
proc newStringStream*(s: string = ""): StringStream =
## creates a new stream from the string `s`.
new(result)
result.data = s
@ -244,27 +248,28 @@ proc newStringStream*(s: string = ""): PStringStream =
when not defined(js):
type
PFileStream* = ref TFileStream ## a stream that encapsulates a `TFile`
TFileStream* = object of TStream
FileStream* = ref FileStreamObj ## a stream that encapsulates a `TFile`
FileStreamObj* = object of Stream
f: File
{.deprecated: [PFileStream: FileStream, TFileStream: FileStreamObj].}
proc fsClose(s: PStream) =
if PFileStream(s).f != nil:
close(PFileStream(s).f)
PFileStream(s).f = nil
proc fsFlush(s: PStream) = flushFile(PFileStream(s).f)
proc fsAtEnd(s: PStream): bool = return endOfFile(PFileStream(s).f)
proc fsSetPosition(s: PStream, pos: int) = setFilePos(PFileStream(s).f, pos)
proc fsGetPosition(s: PStream): int = return int(getFilePos(PFileStream(s).f))
proc fsClose(s: Stream) =
if FileStream(s).f != nil:
close(FileStream(s).f)
FileStream(s).f = nil
proc fsFlush(s: Stream) = flushFile(FileStream(s).f)
proc fsAtEnd(s: Stream): bool = return endOfFile(FileStream(s).f)
proc fsSetPosition(s: Stream, pos: int) = setFilePos(FileStream(s).f, pos)
proc fsGetPosition(s: Stream): int = return int(getFilePos(FileStream(s).f))
proc fsReadData(s: PStream, buffer: pointer, bufLen: int): int =
result = readBuffer(PFileStream(s).f, buffer, bufLen)
proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
result = readBuffer(FileStream(s).f, buffer, bufLen)
proc fsWriteData(s: PStream, buffer: pointer, bufLen: int) =
if writeBuffer(PFileStream(s).f, buffer, bufLen) != bufLen:
proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) =
if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen:
raise newEIO("cannot write to stream")
proc newFileStream*(f: File): PFileStream =
proc newFileStream*(f: File): FileStream =
## creates a new stream from the file `f`.
new(result)
result.f = f
@ -276,7 +281,7 @@ when not defined(js):
result.writeDataImpl = fsWriteData
result.flushImpl = fsFlush
proc newFileStream*(filename: string, mode: FileMode): PFileStream =
proc newFileStream*(filename: string, mode: FileMode): FileStream =
## creates a new stream from the file named `filename` with the mode `mode`.
## If the file cannot be opened, nil is returned. See the `system
## <system.html>`_ module for a list of available TFileMode enums.
@ -288,45 +293,47 @@ when true:
discard
else:
type
TFileHandle* = cint ## Operating system file handle
PFileHandleStream* = ref TFileHandleStream
TFileHandleStream* = object of TStream
handle*: TFileHandle
FileHandleStream* = ref FileHandleStreamObj
FileHandleStreamObj* = object of Stream
handle*: FileHandle
pos: int
proc newEOS(msg: string): ref EOS =
{.deprecated: [PFileHandleStream: FileHandleStream,
TFileHandleStream: FileHandleStreamObj].}
proc newEOS(msg: string): ref OSError =
new(result)
result.msg = msg
proc hsGetPosition(s: PFileHandleStream): int =
proc hsGetPosition(s: FileHandleStream): int =
return s.pos
when defined(windows):
# do not import windows as this increases compile times:
nil
discard
else:
import posix
proc hsSetPosition(s: PFileHandleStream, pos: int) =
proc hsSetPosition(s: FileHandleStream, pos: int) =
discard lseek(s.handle, pos, SEEK_SET)
proc hsClose(s: PFileHandleStream) = discard close(s.handle)
proc hsAtEnd(s: PFileHandleStream): bool =
proc hsClose(s: FileHandleStream) = discard close(s.handle)
proc hsAtEnd(s: FileHandleStream): bool =
var pos = hsGetPosition(s)
var theEnd = lseek(s.handle, 0, SEEK_END)
result = pos >= theEnd
hsSetPosition(s, pos) # set position back
proc hsReadData(s: PFileHandleStream, buffer: pointer, bufLen: int): int =
proc hsReadData(s: FileHandleStream, buffer: pointer, bufLen: int): int =
result = posix.read(s.handle, buffer, bufLen)
inc(s.pos, result)
proc hsWriteData(s: PFileHandleStream, buffer: pointer, bufLen: int) =
proc hsWriteData(s: FileHandleStream, buffer: pointer, bufLen: int) =
if posix.write(s.handle, buffer, bufLen) != bufLen:
raise newEIO("cannot write to stream")
inc(s.pos, bufLen)
proc newFileHandleStream*(handle: TFileHandle): PFileHandleStream =
proc newFileHandleStream*(handle: FileHandle): FileHandleStream =
new(result)
result.handle = handle
result.pos = 0
@ -338,9 +345,9 @@ else:
result.writeData = hsWriteData
proc newFileHandleStream*(filename: string,
mode: TFileMode): PFileHandleStream =
when defined(windows):
nil
mode: FileMode): FileHandleStream =
when defined(windows):
discard
else:
var flags: cint
case mode

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -18,20 +18,23 @@ import
include "system/inclrtl"
type
TStringTableMode* = enum ## describes the tables operation mode
StringTableMode* = enum ## describes the tables operation mode
modeCaseSensitive, ## the table is case sensitive
modeCaseInsensitive, ## the table is case insensitive
modeStyleInsensitive ## the table is style insensitive
TKeyValuePair = tuple[key, val: string]
TKeyValuePairSeq = seq[TKeyValuePair]
TStringTable* = object of RootObj
KeyValuePair = tuple[key, val: string]
KeyValuePairSeq = seq[KeyValuePair]
StringTableObj* = object of RootObj
counter: int
data: TKeyValuePairSeq
mode: TStringTableMode
data: KeyValuePairSeq
mode: StringTableMode
PStringTable* = ref TStringTable ## use this type to declare string tables
StringTableRef* = ref StringTableObj ## use this type to declare string tables
proc len*(t: PStringTable): int {.rtl, extern: "nst$1".} =
{.deprecated: [TStringTableMode: StringTableMode,
TStringTable: StringTableObj, PStringTable: StringTableRef].}
proc len*(t: StringTableRef): int {.rtl, extern: "nst$1".} =
## returns the number of keys in `t`.
result = t.counter
@ -54,7 +57,7 @@ iterator values*(t: PStringTable): string =
yield t.data[h].val
type
TFormatFlag* = enum ## flags for the `%` operator
FormatFlag* = enum ## flags for the `%` operator
useEnvironment, ## use environment variable if the ``$key``
## is not found in the table
useEmpty, ## use the empty string as a default, thus it
@ -63,6 +66,8 @@ type
useKey ## do not replace ``$key`` if it is not found
## in the table (or in the environment)
{.deprecated: [TFormatFlag: FormatFlag].}
# implementation
const

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -23,7 +23,7 @@ import parseutils
include "system/inclrtl"
type
TCharSet* = set[char] # for compatibility with Nim
TCharSet* {.deprecated.} = set[char] # for compatibility with Nim
const
Whitespace* = {' ', '\t', '\v', '\r', '\l', '\f'}
@ -54,7 +54,7 @@ const
## make the `find() proc <#find,string,set[char],int>`_ find **invalid**
## characters in strings. Example:
##
## .. code-block:: nimrod
## .. code-block:: nim
## let invalid = AllChars - Digits
## doAssert "01234".find(invalid) == -1
## doAssert "01A34".find(invalid) == 2
@ -205,7 +205,7 @@ iterator split*(s: string, seps: set[char] = Whitespace): string =
## a single split point and leading/trailing separators will be ignored.
## The following example:
##
## .. code-block:: nimrod
## .. code-block:: nim
## for word in split(" this is an example "):
## writeln(stdout, word)
##
@ -219,13 +219,13 @@ iterator split*(s: string, seps: set[char] = Whitespace): string =
##
## And the following code:
##
## .. code-block:: nimrod
## .. code-block:: nim
## for word in split(";;this;is;an;;example;;;", {';'}):
## writeln(stdout, word)
##
## ...produces the same output as the first example. The code:
##
## .. code-block:: nimrod
## .. code-block:: nim
## let date = "2012-11-20T22:08:08.398990"
## let separators = {' ', '-', ':', 'T'}
## for number in split(date, separators):
@ -258,7 +258,7 @@ iterator split*(s: string, sep: char): string =
## characters, this proc will not coalesce groups of the
## separator, returning a string for each found character. The code:
##
## .. code-block:: nimrod
## .. code-block:: nim
## for word in split(";;this;is;an;;example;;;", ';'):
## writeln(stdout, word)
##
@ -308,13 +308,13 @@ iterator splitLines*(s: string): string =
##
## Example:
##
## .. code-block:: nimrod
## .. code-block:: nim
## for line in splitLines("\nthis\nis\nan\n\nexample\n"):
## writeln(stdout, line)
##
## Results in:
##
## .. code-block:: nimrod
## .. code-block:: nim
## ""
## "this"
## "is"
@ -417,7 +417,7 @@ proc parseInt*(s: string): int {.noSideEffect, procvar,
rtl, extern: "nsuParseInt".} =
## Parses a decimal integer value contained in `s`.
##
## If `s` is not a valid integer, `EInvalidValue` is raised.
## If `s` is not a valid integer, `ValueError` is raised.
var L = parseutils.parseInt(s, result, 0)
if L != s.len or L == 0:
raise newException(ValueError, "invalid integer: " & s)
@ -426,7 +426,7 @@ proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, procvar,
rtl, extern: "nsuParseBiggestInt".} =
## Parses a decimal integer value contained in `s`.
##
## If `s` is not a valid integer, `EInvalidValue` is raised.
## If `s` is not a valid integer, `ValueError` is raised.
var L = parseutils.parseBiggestInt(s, result, 0)
if L != s.len or L == 0:
raise newException(ValueError, "invalid integer: " & s)
@ -434,7 +434,7 @@ proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, procvar,
proc parseFloat*(s: string): float {.noSideEffect, procvar,
rtl, extern: "nsuParseFloat".} =
## Parses a decimal floating point value contained in `s`. If `s` is not
## a valid floating point number, `EInvalidValue` is raised. ``NAN``,
## a valid floating point number, `ValueError` is raised. ``NAN``,
## ``INF``, ``-INF`` are also supported (case insensitive comparison).
var L = parseutils.parseFloat(s, result, 0)
if L != s.len or L == 0:
@ -444,7 +444,7 @@ proc parseHexInt*(s: string): int {.noSideEffect, procvar,
rtl, extern: "nsuParseHexInt".} =
## Parses a hexadecimal integer value contained in `s`.
##
## If `s` is not a valid integer, `EInvalidValue` is raised. `s` can have one
## If `s` is not a valid integer, `ValueError` is raised. `s` can have one
## of the following optional prefixes: ``0x``, ``0X``, ``#``. Underscores
## within `s` are ignored.
var i = 0
@ -471,7 +471,7 @@ proc parseBool*(s: string): bool =
## If ``s`` is one of the following values: ``y, yes, true, 1, on``, then
## returns `true`. If ``s`` is one of the following values: ``n, no, false,
## 0, off``, then returns `false`. If ``s`` is something else a
## ``EInvalidValue`` exception is raised.
## ``ValueError`` exception is raised.
case normalize(s)
of "y", "yes", "true", "1", "on": result = true
of "n", "no", "false", "0", "off": result = false
@ -480,7 +480,7 @@ proc parseBool*(s: string): bool =
proc parseEnum*[T: enum](s: string): T =
## Parses an enum ``T``.
##
## Raises ``EInvalidValue`` for an invalid value in `s`. The comparison is
## Raises ``ValueError`` for an invalid value in `s`. The comparison is
## done in a style insensitive way.
for e in low(T)..high(T):
if cmpIgnoreStyle(s, $e) == 0:
@ -502,7 +502,7 @@ proc repeatChar*(count: int, c: char = ' '): string {.noSideEffect,
## Returns a string of length `count` consisting only of
## the character `c`. You can use this proc to left align strings. Example:
##
## .. code-block:: nimrod
## .. code-block:: nim
## let
## width = 15
## text1 = "Hello user!"
@ -527,7 +527,7 @@ proc align*(s: string, count: int, padding = ' '): string {.
## returned unchanged. If you need to left align a string use the `repeatChar
## proc <#repeatChar>`_. Example:
##
## .. code-block:: nimrod
## .. code-block:: nim
## assert align("abc", 4) == " abc"
## assert align("a", 0) == "a"
## assert align("1232", 6) == " 1232"
@ -547,13 +547,13 @@ iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[
## Substrings are separated by a substring containing only `seps`.
## Examples:
##
## .. code-block:: nimrod
## .. code-block:: nim
## for word in tokenize(" this is an example "):
## writeln(stdout, word)
##
## Results in:
##
## .. code-block:: nimrod
## .. code-block:: nim
## (" ", true)
## ("this", false)
## (" ", true)
@ -676,7 +676,7 @@ proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect,
##
## A shorthand for:
##
## .. code-block:: nimrod
## .. code-block:: nim
## if dest.len > startLen: add(dest, sep)
##
## This is often useful for generating some code where the items need to
@ -684,7 +684,7 @@ proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect,
## `startLen`. The following example creates a string describing
## an array of integers:
##
## .. code-block:: nimrod
## .. code-block:: nim
## var arr = "["
## for x in items([2, 3, 5, 7, 11]):
## addSep(arr, startLen=len("["))
@ -692,7 +692,7 @@ proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect,
## add(arr, "]")
if dest.len > startLen: add(dest, sep)
proc allCharsInSet*(s: string, theSet: TCharSet): bool =
proc allCharsInSet*(s: string, theSet: set[char]): bool =
## Returns true iff each character of `s` is in the set `theSet`.
for c in items(s):
if c notin theSet: return false
@ -739,14 +739,14 @@ proc join*(a: openArray[string]): string {.
result = ""
type
TSkipTable = array[char, int]
SkipTable = array[char, int]
proc preprocessSub(sub: string, a: var TSkipTable) =
proc preprocessSub(sub: string, a: var SkipTable) =
var m = len(sub)
for i in 0..0xff: a[chr(i)] = m+1
for i in 0..m-1: a[sub[i]] = m-i
proc findAux(s, sub: string, start: int, a: TSkipTable): int =
proc findAux(s, sub: string, start: int, a: SkipTable): int =
# Fast "quick search" algorithm:
var
m = len(sub)
@ -762,7 +762,7 @@ proc findAux(s, sub: string, start: int, a: TSkipTable): int =
return -1
proc find*(s, sub: string, start: int = 0): int {.noSideEffect,
rtl, extern: "nsuFindStr", operator: 6.} =
rtl, extern: "nsuFindStr".} =
## Searches for `sub` in `s` starting at position `start`.
##
## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
@ -827,9 +827,9 @@ proc contains*(s: string, chars: set[char]): bool {.noSideEffect.} =
return find(s, chars) >= 0
proc replace*(s, sub: string, by = ""): string {.noSideEffect,
rtl, extern: "nsuReplaceStr", operator: 1.} =
rtl, extern: "nsuReplaceStr".} =
## Replaces `sub` in `s` by the string `by`.
var a {.noinit.}: TSkipTable
var a {.noinit.}: SkipTable
result = ""
preprocessSub(sub, a)
var i = 0
@ -862,7 +862,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
## (comparable to ``\\w`` in regular expressions), otherwise it is not
## replaced.
const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
var a {.noinit.}: TSkipTable
var a {.noinit.}: SkipTable
result = ""
preprocessSub(sub, a)
var i = 0
@ -899,7 +899,7 @@ proc parseOctInt*(s: string): int {.noSideEffect,
rtl, extern: "nsuParseOctInt".} =
## Parses an octal integer value contained in `s`.
##
## If `s` is not a valid integer, `EInvalidValue` is raised. `s` can have one
## If `s` is not a valid integer, `ValueError` is raised. `s` can have one
## of the following optional prefixes: ``0o``, ``0O``. Underscores within
## `s` are ignored.
var i = 0
@ -999,7 +999,7 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
## operations.
##
## If `s` does not begin with ``prefix`` and end with ``suffix`` a
## EInvalidValue exception will be raised.
## ValueError exception will be raised.
result = newStringOfCap(s.len)
var i = 0
if s[0 .. prefix.len-1] != prefix:
@ -1138,12 +1138,14 @@ proc c_sprintf(buf, frmt: cstring) {.header: "<stdio.h>", importc: "sprintf",
varargs, noSideEffect.}
type
TFloatFormat* = enum ## the different modes of floating point formating
FloatFormatMode* = enum ## the different modes of floating point formating
ffDefault, ## use the shorter floating point notation
ffDecimal, ## use decimal floating point notation
ffScientific ## use scientific notation (using ``e`` character)
proc formatBiggestFloat*(f: BiggestFloat, format: TFloatFormat = ffDefault,
{.deprecated: [TFloatFormat: FloatFormatMode].}
proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
precision: range[0..32] = 16): string {.
noSideEffect, operator: 2, rtl, extern: "nsu$1".} =
## Converts a floating point value `f` to a string.
@ -1174,7 +1176,7 @@ proc formatBiggestFloat*(f: BiggestFloat, format: TFloatFormat = ffDefault,
c_sprintf(buf, frmtstr, f)
result = $buf
proc formatFloat*(f: float, format: TFloatFormat = ffDefault,
proc formatFloat*(f: float, format: FloatFormatMode = ffDefault,
precision: range[0..32] = 16): string {.
noSideEffect, operator: 2, rtl, extern: "nsu$1".} =
## Converts a floating point value `f` to a string.
@ -1190,7 +1192,7 @@ proc formatFloat*(f: float, format: TFloatFormat = ffDefault,
proc formatSize*(bytes: BiggestInt, decimalSep = '.'): string =
## Rounds and formats `bytes`. Examples:
##
## .. code-block:: nimrod
## .. code-block:: nim
##
## formatSize(1'i64 shl 31 + 300'i64) == "2.204GB"
## formatSize(4096) == "4KB"
@ -1280,12 +1282,12 @@ proc `%` *(formatstr: string, a: openArray[string]): string {.noSideEffect,
##
## This is best explained by an example:
##
## .. code-block:: nimrod
## .. code-block:: nim
## "$1 eats $2." % ["The cat", "fish"]
##
## Results in:
##
## .. code-block:: nimrod
## .. code-block:: nim
## "The cat eats fish."
##
## The substitution variables (the thing after the ``$``) are enumerated
@ -1294,7 +1296,7 @@ proc `%` *(formatstr: string, a: openArray[string]): string {.noSideEffect,
## The notation ``$#`` can be used to refer to the next substitution
## variable:
##
## .. code-block:: nimrod
## .. code-block:: nim
## "$# eats $#." % ["The cat", "fish"]
##
## Substitution variables can also be words (that is
@ -1302,15 +1304,15 @@ proc `%` *(formatstr: string, a: openArray[string]): string {.noSideEffect,
## indices are keys and with odd indices are the corresponding values.
## An example:
##
## .. code-block:: nimrod
## .. code-block:: nim
## "$animal eats $food." % ["animal", "The cat", "food", "fish"]
##
## Results in:
##
## .. code-block:: nimrod
## .. code-block:: nim
## "The cat eats fish."
##
## The variables are compared with `cmpIgnoreStyle`. `EInvalidValue` is
## The variables are compared with `cmpIgnoreStyle`. `ValueError` is
## raised if an ill-formed format string has been passed to the `%` operator.
result = newStringOfCap(formatstr.len + a.len shl 4)
addf(result, formatstr, a)
@ -1350,7 +1352,7 @@ when isMainModule:
doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc"
type TMyEnum = enum enA, enB, enC, enuD, enE
doAssert parseEnum[TMyEnum]("enu_D") == enuD
type MyEnum = enum enA, enB, enC, enuD, enE
doAssert parseEnum[MyEnum]("enu_D") == enuD
doAssert parseEnum("invalid enum value", enC) == enC

View file

@ -1,13 +1,13 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nimrod support for `substitution expressions`:idx: (`subex`:idx:).
## Nim support for `substitution expressions`:idx: (`subex`:idx:).
##
## .. include:: ../doc/subexes.txt
##
@ -28,11 +28,13 @@ proc findNormalized(x: string, inArray: openarray[string]): int =
return -1
type
EInvalidSubex* = object of EInvalidValue ## exception that is raised for
## an invalid subex
SubexError* = object of ValueError ## exception that is raised for
## an invalid subex
{.deprecated: [EInvalidSubex: SubexError].}
proc raiseInvalidFormat(msg: string) {.noinline.} =
raise newException(EInvalidSubex, "invalid format string: " & msg)
raise newException(SubexError, "invalid format string: " & msg)
type
TFormatParser = object {.pure, final.}
@ -291,14 +293,16 @@ proc scanDollar(p: var TFormatParser, a: openarray[string], s: var string) =
type
TSubex* = distinct string ## string that contains a substitution expression
Subex* = distinct string ## string that contains a substitution expression
proc subex*(s: string): TSubex =
{.deprecated: [TSubex: Subex].}
proc subex*(s: string): Subex =
## constructs a *substitution expression* from `s`. Currently this performs
## no syntax checking but this may change in later versions.
result = TSubex(s)
result = Subex(s)
proc addf*(s: var string, formatstr: TSubex, a: varargs[string, `$`]) {.
proc addf*(s: var string, formatstr: Subex, a: varargs[string, `$`]) {.
noSideEffect, rtl, extern: "nfrmtAddf".} =
## The same as ``add(s, formatstr % a)``, but more efficient.
var p: TFormatParser
@ -312,7 +316,7 @@ proc addf*(s: var string, formatstr: TSubex, a: varargs[string, `$`]) {.
emitChar(p, s, p.f[i])
inc(i)
proc `%` *(formatstr: TSubex, a: openarray[string]): string {.noSideEffect,
proc `%` *(formatstr: Subex, a: openarray[string]): string {.noSideEffect,
rtl, extern: "nfrmtFormatOpenArray".} =
## The `substitution`:idx: operator performs string substitutions in
## `formatstr` and returns a modified `formatstr`. This is often called
@ -321,13 +325,13 @@ proc `%` *(formatstr: TSubex, a: openarray[string]): string {.noSideEffect,
result = newStringOfCap(formatstr.string.len + a.len shl 4)
addf(result, formatstr, a)
proc `%` *(formatstr: TSubex, a: string): string {.noSideEffect,
proc `%` *(formatstr: Subex, a: string): string {.noSideEffect,
rtl, extern: "nfrmtFormatSingleElem".} =
## This is the same as ``formatstr % [a]``.
result = newStringOfCap(formatstr.string.len + a.len)
addf(result, formatstr, [a])
proc format*(formatstr: TSubex, a: varargs[string, `$`]): string {.noSideEffect,
proc format*(formatstr: Subex, a: varargs[string, `$`]): string {.noSideEffect,
rtl, extern: "nfrmtFormatVarargs".} =
## The `substitution`:idx: operator performs string substitutions in
## `formatstr` and returns a modified `formatstr`. This is often called

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -27,11 +27,11 @@ when defined(windows):
var hTemp = GetStdHandle(STD_OUTPUT_HANDLE)
if DuplicateHandle(GetCurrentProcess(), hTemp, GetCurrentProcess(),
addr(conHandle), 0, 1, DUPLICATE_SAME_ACCESS) == 0:
osError(osLastError())
raiseOSError(osLastError())
proc getCursorPos(): tuple [x,y: int] =
var c: TCONSOLESCREENBUFFERINFO
if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: osError(osLastError())
if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: raiseOSError(osLastError())
return (int(c.dwCursorPosition.x), int(c.dwCursorPosition.y))
proc getAttributes(): int16 =
@ -51,7 +51,7 @@ proc setCursorPos*(x, y: int) =
var c: TCOORD
c.x = int16(x)
c.y = int16(y)
if SetConsoleCursorPosition(conHandle, c) == 0: osError(osLastError())
if SetConsoleCursorPosition(conHandle, c) == 0: raiseOSError(osLastError())
else:
stdout.write("\e[" & $y & ';' & $x & 'f')
@ -61,10 +61,10 @@ proc setCursorXPos*(x: int) =
when defined(windows):
var scrbuf: TCONSOLESCREENBUFFERINFO
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: osError(osLastError())
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: raiseOSError(osLastError())
var origin = scrbuf.dwCursorPosition
origin.x = int16(x)
if SetConsoleCursorPosition(conHandle, origin) == 0: osError(osLastError())
if SetConsoleCursorPosition(conHandle, origin) == 0: raiseOSError(osLastError())
else:
stdout.write("\e[" & $x & 'G')
@ -75,10 +75,10 @@ when defined(windows):
when defined(windows):
var scrbuf: TCONSOLESCREENBUFFERINFO
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: osError(osLastError())
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: raiseOSError(osLastError())
var origin = scrbuf.dwCursorPosition
origin.y = int16(y)
if SetConsoleCursorPosition(conHandle, origin) == 0: osError(osLastError())
if SetConsoleCursorPosition(conHandle, origin) == 0: raiseOSError(osLastError())
else:
discard
@ -155,18 +155,18 @@ proc eraseLine* =
var scrbuf: TCONSOLESCREENBUFFERINFO
var numwrote: DWORD
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: osError(osLastError())
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: raiseOSError(osLastError())
var origin = scrbuf.dwCursorPosition
origin.x = 0'i16
if SetConsoleCursorPosition(conHandle, origin) == 0: osError(osLastError())
if SetConsoleCursorPosition(conHandle, origin) == 0: raiseOSError(osLastError())
var ht = scrbuf.dwSize.Y - origin.Y
var wt = scrbuf.dwSize.X - origin.X
if FillConsoleOutputCharacter(hStdout,' ', ht*wt,
origin, addr(numwrote)) == 0:
osError(osLastError())
raiseOSError(osLastError())
if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, ht * wt,
scrbuf.dwCursorPosition, addr(numwrote)) == 0:
osError(osLastError())
raiseOSError(osLastError())
else:
stdout.write("\e[2K")
setCursorXPos(0)
@ -178,14 +178,14 @@ proc eraseScreen* =
var numwrote: DWORD
var origin: TCOORD # is inititalized to 0, 0
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: osError(osLastError())
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: raiseOSError(osLastError())
if FillConsoleOutputCharacter(hStdout, ' ', scrbuf.dwSize.X*scrbuf.dwSize.Y,
origin, addr(numwrote)) == 0:
osError(osLastError())
raiseOSError(osLastError())
if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes,
scrbuf.dwSize.X * scrbuf.dwSize.Y,
origin, addr(numwrote)) == 0:
osError(osLastError())
raiseOSError(osLastError())
setCursorXPos(0)
else:
stdout.write("\e[2J")
@ -199,7 +199,7 @@ proc resetAttributes* {.noconv.} =
stdout.write("\e[0m")
type
TStyle* = enum ## different styles for text output
Style* = enum ## different styles for text output
styleBright = 1, ## bright text
styleDim, ## dim text
styleUnknown, ## unknown
@ -208,6 +208,8 @@ type
styleReverse = 7, ## unknown
styleHidden ## hidden text
{.deprecated: [TStyle: Style].}
when not defined(windows):
var
# XXX: These better be thread-local
@ -244,7 +246,7 @@ proc writeStyled*(txt: string, style: set[TStyle] = {styleBright}) =
stdout.write("\e[" & $ord(gBG) & 'm')
type
TForegroundColor* = enum ## terminal's foreground colors
ForegroundColor* = enum ## terminal's foreground colors
fgBlack = 30, ## black
fgRed, ## red
fgGreen, ## green
@ -254,7 +256,7 @@ type
fgCyan, ## cyan
fgWhite ## white
TBackgroundColor* = enum ## terminal's background colors
BackgroundColor* = enum ## terminal's background colors
bgBlack = 40, ## black
bgRed, ## red
bgGreen, ## green
@ -264,13 +266,16 @@ type
bgCyan, ## cyan
bgWhite ## white
proc setForegroundColor*(fg: TForegroundColor, bright=false) =
{.deprecated: [TForegroundColor: ForegroundColor,
TBackgroundColor: BackgroundColor].}
proc setForegroundColor*(fg: ForegroundColor, bright=false) =
## sets the terminal's foreground color
when defined(windows):
var old = getAttributes() and not 0x0007
if bright:
old = old or FOREGROUND_INTENSITY
const lookup: array [TForegroundColor, int] = [
const lookup: array [ForegroundColor, int] = [
0,
(FOREGROUND_RED),
(FOREGROUND_GREEN),
@ -285,13 +290,13 @@ proc setForegroundColor*(fg: TForegroundColor, bright=false) =
if bright: inc(gFG, 60)
stdout.write("\e[" & $gFG & 'm')
proc setBackgroundColor*(bg: TBackgroundColor, bright=false) =
proc setBackgroundColor*(bg: BackgroundColor, bright=false) =
## sets the terminal's background color
when defined(windows):
var old = getAttributes() and not 0x0070
if bright:
old = old or BACKGROUND_INTENSITY
const lookup: array [TBackgroundColor, int] = [
const lookup: array [BackgroundColor, int] = [
0,
(BACKGROUND_RED),
(BACKGROUND_GREEN),
@ -306,22 +311,22 @@ proc setBackgroundColor*(bg: TBackgroundColor, bright=false) =
if bright: inc(gBG, 60)
stdout.write("\e[" & $gBG & 'm')
proc isatty*(f: TFile): bool =
proc isatty*(f: File): bool =
## returns true if `f` is associated with a terminal device.
when defined(posix):
proc isatty(fildes: TFileHandle): cint {.
proc isatty(fildes: FileHandle): cint {.
importc: "isatty", header: "<unistd.h>".}
else:
proc isatty(fildes: TFileHandle): cint {.
proc isatty(fildes: FileHandle): cint {.
importc: "_isatty", header: "<io.h>".}
result = isatty(fileHandle(f)) != 0'i32
result = isatty(getFileHandle(f)) != 0'i32
proc styledEchoProcessArg(s: string) = write stdout, s
proc styledEchoProcessArg(style: TStyle) = setStyle({style})
proc styledEchoProcessArg(style: set[TStyle]) = setStyle style
proc styledEchoProcessArg(color: TForegroundColor) = setForegroundColor color
proc styledEchoProcessArg(color: TBackgroundColor) = setBackgroundColor color
proc styledEchoProcessArg(s: string) = write stdout, s
proc styledEchoProcessArg(style: Style) = setStyle({style})
proc styledEchoProcessArg(style: set[Style]) = setStyle style
proc styledEchoProcessArg(color: ForegroundColor) = setForegroundColor color
proc styledEchoProcessArg(color: BackgroundColor) = setBackgroundColor color
macro styledEcho*(m: varargs[expr]): stmt =
## to be documented.

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -21,9 +21,9 @@ import
include "system/inclrtl"
type
TMonth* = enum ## represents a month
Month* = enum ## represents a month
mJan, mFeb, mMar, mApr, mMay, mJun, mJul, mAug, mSep, mOct, mNov, mDec
TWeekDay* = enum ## represents a weekday
WeekDay* = enum ## represents a weekday
dMon, dTue, dWed, dThu, dFri, dSat, dSun
var
@ -32,12 +32,12 @@ var
when defined(posix) and not defined(JS):
type
TTimeImpl {.importc: "time_t", header: "<sys/time.h>".} = int
TTime* = distinct TTimeImpl ## distinct type that represents a time
## measured as number of seconds since the epoch
TimeImpl {.importc: "time_t", header: "<sys/time.h>".} = int
Time* = distinct TimeImpl ## distinct type that represents a time
## measured as number of seconds since the epoch
Ttimeval {.importc: "struct timeval", header: "<sys/select.h>",
final, pure.} = object ## struct timeval
Timeval {.importc: "struct timeval",
header: "<sys/select.h>".} = object ## struct timeval
tv_sec: int ## Seconds.
tv_usec: int ## Microseconds.
@ -45,7 +45,7 @@ when defined(posix) and not defined(JS):
# Ok, we could, but I don't want circular dependencies.
# And gettimeofday() is not defined in the posix module anyway. Sigh.
proc posix_gettimeofday(tp: var Ttimeval, unused: pointer = nil) {.
proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {.
importc: "gettimeofday", header: "<sys/time.h>".}
elif defined(windows):
@ -53,16 +53,16 @@ elif defined(windows):
when defined(vcc):
# newest version of Visual C++ defines time_t to be of 64 bits
type TTimeImpl {.importc: "time_t", header: "<time.h>".} = int64
type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64
else:
type TTimeImpl {.importc: "time_t", header: "<time.h>".} = int32
type TimeImpl {.importc: "time_t", header: "<time.h>".} = int32
type
TTime* = distinct TTimeImpl
Time* = distinct TimeImpl
elif defined(JS):
type
TTime* {.final, importc.} = object
Time* {.importc.} = object
getDay: proc (): int {.tags: [], raises: [], gcsafe.}
getFullYear: proc (): int {.tags: [], raises: [], gcsafe.}
getHours: proc (): int {.tags: [], raises: [], gcsafe.}
@ -82,7 +82,7 @@ elif defined(JS):
getUTCSeconds: proc (): int {.tags: [], raises: [], gcsafe.}
getUTCDay: proc (): int {.tags: [], raises: [], gcsafe.}
getYear: proc (): int {.tags: [], raises: [], gcsafe.}
parse: proc (s: cstring): TTime {.tags: [], raises: [], gcsafe.}
parse: proc (s: cstring): Time {.tags: [], raises: [], gcsafe.}
setDate: proc (x: int) {.tags: [], raises: [], gcsafe.}
setFullYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
setHours: proc (x: int) {.tags: [], raises: [], gcsafe.}
@ -103,7 +103,7 @@ elif defined(JS):
toLocaleString: proc (): cstring {.tags: [], raises: [], gcsafe.}
type
TTimeInfo* = object of RootObj ## represents a time in different parts
TimeInfo* = object of RootObj ## represents a time in different parts
second*: range[0..61] ## The number of seconds after the minute,
## normally in the range 0 to 59, but can
## be up to 61 to allow for leap seconds.
@ -112,9 +112,9 @@ type
hour*: range[0..23] ## The number of hours past midnight,
## in the range 0 to 23.
monthday*: range[1..31] ## The day of the month, in the range 1 to 31.
month*: TMonth ## The current month.
month*: Month ## The current month.
year*: range[-10_000..10_000] ## The current year.
weekday*: TWeekDay ## The current day of the week.
weekday*: WeekDay ## The current day of the week.
yearday*: range[0..365] ## The number of days since January 1,
## in the range 0 to 365.
## Always 0 if the target is JS.
@ -127,7 +127,7 @@ type
## I make some assumptions about the data in here. Either
## everything should be positive or everything negative. Zero is
## fine too. Mixed signs will lead to unexpected results.
TTimeInterval* {.pure.} = object ## a time interval
TimeInterval* = object ## a time interval
miliseconds*: int ## The number of miliseconds
seconds*: int ## The number of seconds
minutes*: int ## The number of minutes
@ -136,55 +136,58 @@ type
months*: int ## The number of months
years*: int ## The number of years
proc getTime*(): TTime {.tags: [TimeEffect], gcsafe.}
{.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time, TTimeval: Timeval,
TTimeInterval: TimeInterval, TTimeInfo: TimeInfo].}
proc getTime*(): Time {.tags: [TimeEffect], gcsafe.}
## gets the current calendar time as a UNIX epoch value (number of seconds
## elapsed since 1970) with integer precission. Use epochTime for higher
## resolution.
proc getLocalTime*(t: TTime): TTimeInfo {.tags: [TimeEffect], raises: [], gcsafe.}
proc getLocalTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.}
## converts the calendar time `t` to broken-time representation,
## expressed relative to the user's specified time zone.
proc getGMTime*(t: TTime): TTimeInfo {.tags: [TimeEffect], raises: [], gcsafe.}
proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.}
## converts the calendar time `t` to broken-down time representation,
## expressed in Coordinated Universal Time (UTC).
proc timeInfoToTime*(timeInfo: TTimeInfo): TTime {.tags: [], gcsafe.}
proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], gcsafe.}
## 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.
proc fromSeconds*(since1970: float): TTime {.tags: [], raises: [], gcsafe.}
proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], gcsafe.}
## Takes a float which contains the number of seconds since the unix epoch and
## returns a time object.
proc fromSeconds*(since1970: int64): TTime {.tags: [], raises: [], gcsafe.} =
proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], gcsafe.} =
## Takes an int which contains the number of seconds since the unix epoch and
## returns a time object.
fromSeconds(float(since1970))
proc toSeconds*(time: TTime): float {.tags: [], raises: [], gcsafe.}
proc toSeconds*(time: Time): float {.tags: [], raises: [], gcsafe.}
## Returns the time in seconds since the unix epoch.
proc `$` *(timeInfo: TTimeInfo): string {.tags: [], raises: [], gcsafe.}
## converts a `TTimeInfo` object to a string representation.
proc `$` *(time: TTime): string {.tags: [], raises: [], gcsafe.}
proc `$` *(timeInfo: TimeInfo): string {.tags: [], raises: [], gcsafe.}
## converts a `TimeInfo` object to a string representation.
proc `$` *(time: Time): string {.tags: [], raises: [], gcsafe.}
## converts a calendar time to a string representation.
proc `-`*(a, b: TTime): int64 {.
proc `-`*(a, b: Time): int64 {.
rtl, extern: "ntDiffTime", tags: [], raises: [].}
## computes the difference of two calendar times. Result is in seconds.
proc `<`*(a, b: TTime): bool {.
proc `<`*(a, b: Time): bool {.
rtl, extern: "ntLtTime", tags: [], raises: [].} =
## returns true iff ``a < b``, that is iff a happened before b.
result = a - b < 0
proc `<=` * (a, b: TTime): bool {.
proc `<=` * (a, b: Time): bool {.
rtl, extern: "ntLeTime", tags: [], raises: [].}=
## returns true iff ``a <= b``.
result = a - b <= 0
proc `==`*(a, b: TTime): bool {.
proc `==`*(a, b: Time): bool {.
rtl, extern: "ntEqTime", tags: [], raises: [].} =
## returns true if ``a == b``, that is if both times represent the same value
result = a - b == 0
@ -203,8 +206,8 @@ proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], gcsafe.}
## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
proc initInterval*(miliseconds, seconds, minutes, hours, days, months,
years: int = 0): TTimeInterval =
## creates a new ``TTimeInterval``.
years: int = 0): TimeInterval =
## creates a new ``TimeInterval``.
result.miliseconds = miliseconds
result.seconds = seconds
result.minutes = minutes
@ -234,7 +237,7 @@ proc getDaysInMonth*(month: TMonth, year: int): int =
of mApr, mJun, mSep, mNov: result = 30
else: result = 31
proc toSeconds(a: TTimeInfo, interval: TTimeInterval): float =
proc toSeconds(a: TimeInfo, interval: TimeInterval): float =
## Calculates how many seconds the interval is worth by adding up
## all the fields
@ -257,7 +260,7 @@ proc toSeconds(a: TTimeInfo, interval: TTimeInterval): float =
result += float(newinterv.seconds)
result += newinterv.miliseconds / 1000
proc `+`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo =
proc `+`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
## adds ``interval`` time.
##
## **Note:** This has been only briefly tested and it may not be
@ -269,7 +272,7 @@ proc `+`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo =
else:
result = getLocalTime(fromSeconds(t + secs))
proc `-`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo =
proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
## subtracts ``interval`` time.
##
## **Note:** This has been only briefly tested, it is inaccurate especially
@ -314,38 +317,36 @@ when not defined(JS):
yearday {.importc: "tm_yday".},
isdst {.importc: "tm_isdst".}: cint
PTimeInfo = ptr StructTM
PTime = ptr TTime
TimeInfoPtr = ptr StructTM
Clock {.importc: "clock_t".} = distinct int
TClock {.importc: "clock_t".} = distinct int
proc localtime(timer: PTime): PTimeInfo {.
proc localtime(timer: ptr Time): TimeInfoPtr {.
importc: "localtime", header: "<time.h>", tags: [].}
proc gmtime(timer: PTime): PTimeInfo {.
proc gmtime(timer: ptr Time): TimeInfoPtr {.
importc: "gmtime", header: "<time.h>", tags: [].}
proc timec(timer: PTime): TTime {.
proc timec(timer: ptr Time): Time {.
importc: "time", header: "<time.h>", tags: [].}
proc mktime(t: StructTM): TTime {.
proc mktime(t: StructTM): Time {.
importc: "mktime", header: "<time.h>", tags: [].}
proc asctime(tblock: StructTM): cstring {.
importc: "asctime", header: "<time.h>", tags: [].}
proc ctime(time: PTime): cstring {.
proc ctime(time: ptr Time): cstring {.
importc: "ctime", header: "<time.h>", tags: [].}
# strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {.
# importc: "strftime", header: "<time.h>".}
proc clock(): TClock {.importc: "clock", header: "<time.h>", tags: [TimeEffect].}
proc difftime(a, b: TTime): float {.importc: "difftime", header: "<time.h>",
proc getClock(): Clock {.importc: "clock", header: "<time.h>", tags: [TimeEffect].}
proc difftime(a, b: Time): float {.importc: "difftime", header: "<time.h>",
tags: [].}
var
clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
# our own procs on top of that:
proc tmToTimeInfo(tm: StructTM, local: bool): TTimeInfo =
proc tmToTimeInfo(tm: StructTM, local: bool): TimeInfo =
const
weekDays: array [0..6, TWeekDay] = [
weekDays: array [0..6, WeekDay] = [
dSun, dMon, dTue, dWed, dThu, dFri, dSat]
TTimeInfo(second: int(tm.second),
TimeInfo(second: int(tm.second),
minute: int(tm.minute),
hour: int(tm.hour),
monthday: int(tm.monthday),
@ -364,9 +365,9 @@ when not defined(JS):
timezone: if local: getTimezone() else: 0
)
proc timeInfoToTM(t: TTimeInfo): StructTM =
proc timeInfoToTM(t: TimeInfo): StructTM =
const
weekDays: array [TWeekDay, int8] = [1'i8,2'i8,3'i8,4'i8,5'i8,6'i8,0'i8]
weekDays: array [WeekDay, int8] = [1'i8,2'i8,3'i8,4'i8,5'i8,6'i8,0'i8]
result.second = t.second
result.minute = t.minute
result.hour = t.hour
@ -378,36 +379,36 @@ when not defined(JS):
result.isdst = if t.isDST: 1 else: 0
when not defined(useNimRtl):
proc `-` (a, b: TTime): int64 =
proc `-` (a, b: Time): int64 =
return toBiggestInt(difftime(a, b))
proc getStartMilsecs(): int =
#echo "clocks per sec: ", clocksPerSec, "clock: ", int(clock())
#return clock() div (clocksPerSec div 1000)
#echo "clocks per sec: ", clocksPerSec, "clock: ", int(getClock())
#return getClock() div (clocksPerSec div 1000)
when defined(macosx):
result = toInt(toFloat(int(clock())) / (toFloat(clocksPerSec) / 1000.0))
result = toInt(toFloat(int(getClock())) / (toFloat(clocksPerSec) / 1000.0))
else:
result = int(clock()) div (clocksPerSec div 1000)
result = int(getClock()) div (clocksPerSec div 1000)
when false:
var a: Ttimeval
var a: Timeval
posix_gettimeofday(a)
result = a.tv_sec * 1000'i64 + a.tv_usec div 1000'i64
#echo "result: ", result
proc getTime(): TTime = return timec(nil)
proc getLocalTime(t: TTime): TTimeInfo =
proc getTime(): Time = return timec(nil)
proc getLocalTime(t: Time): TimeInfo =
var a = t
result = tmToTimeInfo(localtime(addr(a))[], true)
# copying is needed anyway to provide reentrancity; thus
# the conversion is not expensive
proc getGMTime(t: TTime): TTimeInfo =
proc getGMTime(t: Time): TimeInfo =
var a = t
result = tmToTimeInfo(gmtime(addr(a))[], false)
# copying is needed anyway to provide reentrancity; thus
# the conversion is not expensive
proc timeInfoToTime(timeInfo: TTimeInfo): TTime =
proc timeInfoToTime(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))
@ -419,12 +420,12 @@ when not defined(JS):
add(result, p[i])
inc(i)
proc `$`(timeInfo: TTimeInfo): string =
proc `$`(timeInfo: TimeInfo): string =
# BUGFIX: asctime returns a newline at the end!
var p = asctime(timeInfoToTM(timeInfo))
result = toStringTillNL(p)
proc `$`(time: TTime): string =
proc `$`(time: Time): string =
# BUGFIX: ctime returns a newline at the end!
var a = time
return toStringTillNL(ctime(addr(a)))
@ -433,13 +434,13 @@ when not defined(JS):
epochDiff = 116444736000000000'i64
rateDiff = 10000000'i64 # 100 nsecs
proc unixTimeToWinTime*(t: TTime): int64 =
## converts a UNIX `TTime` (``time_t``) to a Windows file time
proc unixTimeToWinTime*(t: Time): int64 =
## converts a UNIX `Time` (``time_t``) to a Windows file time
result = int64(t) * rateDiff + epochDiff
proc winTimeToUnixTime*(t: int64): TTime =
## converts a Windows time to a UNIX `TTime` (``time_t``)
result = TTime((t - epochDiff) div rateDiff)
proc winTimeToUnixTime*(t: int64): Time =
## converts a Windows time to a UNIX `Time` (``time_t``)
result = Time((t - epochDiff) div rateDiff)
proc getTzname(): tuple[nonDST, DST: string] =
return ($tzname[0], $tzname[1])
@ -447,9 +448,9 @@ when not defined(JS):
proc getTimezone(): int =
return timezone
proc fromSeconds(since1970: float): TTime = TTime(since1970)
proc fromSeconds(since1970: float): Time = Time(since1970)
proc toSeconds(time: TTime): float = float(time)
proc toSeconds(time: Time): float = float(time)
when not defined(useNimRtl):
proc epochTime(): float =
@ -468,15 +469,15 @@ when not defined(JS):
{.error: "unknown OS".}
proc cpuTime(): float =
result = toFloat(int(clock())) / toFloat(clocksPerSec)
result = toFloat(int(getClock())) / toFloat(clocksPerSec)
elif defined(JS):
proc newDate(): TTime {.importc: "new Date".}
proc internGetTime(): TTime {.importc: "new Date", tags: [].}
proc newDate(): Time {.importc: "new Date".}
proc internGetTime(): Time {.importc: "new Date", tags: [].}
proc newDate(value: float): TTime {.importc: "new Date".}
proc newDate(value: string): TTime {.importc: "new Date".}
proc getTime(): TTime =
proc newDate(value: float): Time {.importc: "new Date".}
proc newDate(value: string): Time {.importc: "new Date".}
proc getTime(): Time =
# Warning: This is something different in JS.
return newDate()
@ -484,7 +485,7 @@ elif defined(JS):
weekDays: array [0..6, TWeekDay] = [
dSun, dMon, dTue, dWed, dThu, dFri, dSat]
proc getLocalTime(t: TTime): TTimeInfo =
proc getLocalTime(t: Time): TimeInfo =
result.second = t.getSeconds()
result.minute = t.getMinutes()
result.hour = t.getHours()
@ -494,7 +495,7 @@ elif defined(JS):
result.weekday = weekDays[t.getDay()]
result.yearday = 0
proc getGMTime(t: TTime): TTimeInfo =
proc getGMTime(t: Time): TimeInfo =
result.second = t.getUTCSeconds()
result.minute = t.getUTCMinutes()
result.hour = t.getUTCHours()
@ -504,7 +505,7 @@ elif defined(JS):
result.weekday = weekDays[t.getUTCDay()]
result.yearday = 0
proc timeInfoToTime*(timeInfo: TTimeInfo): TTime =
proc timeInfoToTime*(timeInfo: TimeInfo): Time =
result = internGetTime()
result.setSeconds(timeInfo.second)
result.setMinutes(timeInfo.minute)
@ -513,10 +514,10 @@ elif defined(JS):
result.setFullYear(timeInfo.year)
result.setDate(timeInfo.monthday)
proc `$`(timeInfo: TTimeInfo): string = return $(TimeInfoToTIme(timeInfo))
proc `$`(time: TTime): string = return $time.toLocaleString()
proc `$`(timeInfo: TimeInfo): string = return $(TimeInfoToTIme(timeInfo))
proc `$`(time: Time): string = return $time.toLocaleString()
proc `-` (a, b: TTime): int64 =
proc `-` (a, b: Time): int64 =
return a.getTime() - b.getTime()
var
@ -526,11 +527,11 @@ elif defined(JS):
## get the miliseconds from the start of the program
return int(getTime() - startMilsecs)
proc valueOf(time: TTime): float {.importcpp: "getTime", tags:[]}
proc valueOf(time: Time): float {.importcpp: "getTime", tags:[]}
proc fromSeconds(since1970: float): TTime = result = newDate(since1970)
proc fromSeconds(since1970: float): Time = result = newDate(since1970)
proc toSeconds(time: TTime): float = result = time.valueOf() / 1000
proc toSeconds(time: Time): float = result = time.valueOf() / 1000
proc getTimezone(): int = result = newDate().getTimezoneOffset()
@ -546,20 +547,20 @@ proc getClockStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} =
result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) &
':' & intToStr(ti.second, 2)
proc `$`*(day: TWeekDay): string =
## stingify operator for ``TWeekDay``.
const lookup: array[TWeekDay, string] = ["Monday", "Tuesday", "Wednesday",
proc `$`*(day: WeekDay): string =
## stingify operator for ``WeekDay``.
const lookup: array[WeekDay, string] = ["Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday", "Sunday"]
return lookup[day]
proc `$`*(m: TMonth): string =
proc `$`*(m: Month): string =
## stingify operator for ``TMonth``.
const lookup: array[TMonth, string] = ["January", "February", "March",
const lookup: array[Month, string] = ["January", "February", "March",
"April", "May", "June", "July", "August", "September", "October",
"November", "December"]
return lookup[m]
proc format_token(info: TTimeInfo, token: string, buf: var string) =
proc formatToken(info: TimeInfo, token: string, buf: var string) =
## Helper of the format proc to parse individual tokens.
##
## Pass the found token in the user input string, and the buffer where the
@ -672,7 +673,7 @@ proc format_token(info: TTimeInfo, token: string, buf: var string) =
raise newException(ValueError, "Invalid format string: " & token)
proc format*(info: TTimeInfo, f: string): string =
proc format*(info: TimeInfo, f: string): string =
## This function formats `info` as specified by `f`. The following format
## specifiers are available:
##
@ -718,7 +719,7 @@ proc format*(info: TTimeInfo, f: string): string =
while true:
case f[i]
of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
format_token(info, currentF, result)
formatToken(info, currentF, result)
currentF = ""
if f[i] == '\0': break
@ -735,7 +736,7 @@ proc format*(info: TTimeInfo, f: string): string =
if currentF.len < 1 or currentF[high(currentF)] == f[i]:
currentF.add(f[i])
else:
format_token(info, currentF, result)
formatToken(info, currentF, result)
dec(i) # Move position back to re-process the character separately.
currentF = ""
@ -764,7 +765,7 @@ when isMainModule:
" ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") ==
"27 27 Mon Monday 4 04 16 16 6 06 1 01 Jan January 29 29 P PM 5 75 975 1975 01975 0 00 00:00 UTC"
when not defined(JS) and sizeof(TTime) == 8:
when not defined(JS) and sizeof(Time) == 8:
var t3 = getGMTime(fromSeconds(889067643645)) # Fri 7 Jun 19:20:45 BST 30143
assert t3.format("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
" ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") ==

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Nimrod Contributors
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -14,13 +14,15 @@
include "system/inclrtl"
type
IRune = int # underlying type of TRune
TRune* = distinct IRune ## type that can hold any Unicode character
TRune16* = distinct int16 ## 16 bit Unicode character
RuneImpl = int # underlying type of Rune
Rune* = distinct RuneImpl ## type that can hold any Unicode character
Rune16* = distinct int16 ## 16 bit Unicode character
{.deprecated: [TRune: Rune, TRune16: Rune16].}
proc `<=%`*(a, b: TRune): bool = return int(a) <=% int(b)
proc `<%`*(a, b: TRune): bool = return int(a) <% int(b)
proc `==`*(a, b: TRune): bool = return int(a) == int(b)
proc `<=%`*(a, b: Rune): bool = return int(a) <=% int(b)
proc `<%`*(a, b: Rune): bool = return int(a) <% int(b)
proc `==`*(a, b: Rune): bool = return int(a) == int(b)
template ones(n: expr): expr = ((1 shl n)-1)
@ -52,17 +54,17 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
## `i` is incremented by the number of bytes that have been processed.
bind ones
if ord(s[i]) <=% 127:
result = TRune(ord(s[i]))
result = Rune(ord(s[i]))
when doInc: inc(i)
elif ord(s[i]) shr 5 == 0b110:
# assert(ord(s[i+1]) shr 6 == 0b10)
result = TRune((ord(s[i]) and (ones(5))) shl 6 or
(ord(s[i+1]) and ones(6)))
result = Rune((ord(s[i]) and (ones(5))) shl 6 or
(ord(s[i+1]) and ones(6)))
when doInc: inc(i, 2)
elif ord(s[i]) shr 4 == 0b1110:
# assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+2]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(4)) shl 12 or
result = Rune((ord(s[i]) and ones(4)) shl 12 or
(ord(s[i+1]) and ones(6)) shl 6 or
(ord(s[i+2]) and ones(6)))
when doInc: inc(i, 3)
@ -70,7 +72,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
# assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+2]) shr 6 == 0b10)
# assert(ord(s[i+3]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(3)) shl 18 or
result = Rune((ord(s[i]) and ones(3)) shl 18 or
(ord(s[i+1]) and ones(6)) shl 12 or
(ord(s[i+2]) and ones(6)) shl 6 or
(ord(s[i+3]) and ones(6)))
@ -80,7 +82,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
# assert(ord(s[i+2]) shr 6 == 0b10)
# assert(ord(s[i+3]) shr 6 == 0b10)
# assert(ord(s[i+4]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(2)) shl 24 or
result = Rune((ord(s[i]) and ones(2)) shl 24 or
(ord(s[i+1]) and ones(6)) shl 18 or
(ord(s[i+2]) and ones(6)) shl 12 or
(ord(s[i+3]) and ones(6)) shl 6 or
@ -92,7 +94,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
# assert(ord(s[i+3]) shr 6 == 0b10)
# assert(ord(s[i+4]) shr 6 == 0b10)
# assert(ord(s[i+5]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(1)) shl 30 or
result = Rune((ord(s[i]) and ones(1)) shl 30 or
(ord(s[i+1]) and ones(6)) shl 24 or
(ord(s[i+2]) and ones(6)) shl 18 or
(ord(s[i+3]) and ones(6)) shl 12 or
@ -100,16 +102,16 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
(ord(s[i+5]) and ones(6)))
when doInc: inc(i, 6)
else:
result = TRune(ord(s[i]))
result = Rune(ord(s[i]))
when doInc: inc(i)
proc runeAt*(s: string, i: int): TRune =
proc runeAt*(s: string, i: int): Rune =
## returns the unicode character in `s` at byte index `i`
fastRuneAt(s, i, result, false)
proc toUTF8*(c: TRune): string {.rtl, extern: "nuc$1".} =
proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
## converts a rune into its UTF8 representation
var i = IRune(c)
var i = RuneImpl(c)
if i <=% 127:
result = newString(1)
result[0] = chr(i)
@ -132,11 +134,11 @@ proc toUTF8*(c: TRune): string {.rtl, extern: "nuc$1".} =
result = newString(1)
result[0] = chr(i)
proc `$`*(rune: TRune): string =
proc `$`*(rune: Rune): string =
## converts a rune to a string
rune.toUTF8
proc `$`*(runes: seq[TRune]): string =
proc `$`*(runes: seq[Rune]): string =
## converts a sequence of runes to a string
result = ""
for rune in runes: result.add(rune.toUTF8)
@ -1100,7 +1102,7 @@ const
0x01f1, 501, #
0x01f3, 499] #
proc binarySearch(c: IRune, tab: openArray[IRune], len, stride: int): int =
proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int =
var n = len
var t = 0
while n > 1:
@ -1115,41 +1117,41 @@ proc binarySearch(c: IRune, tab: openArray[IRune], len, stride: int): int =
return t
return -1
proc toLower*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} =
proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
## Converts `c` into lower case. This works for any Unicode character.
## If possible, prefer `toLower` over `toUpper`.
var c = IRune(c)
var c = RuneImpl(c)
var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]:
return TRune(c + tolowerRanges[p+2] - 500)
return Rune(c + tolowerRanges[p+2] - 500)
p = binarySearch(c, tolowerSinglets, len(tolowerSinglets) div 2, 2)
if p >= 0 and c == tolowerSinglets[p]:
return TRune(c + tolowerSinglets[p+1] - 500)
return TRune(c)
return Rune(c + tolowerSinglets[p+1] - 500)
return Rune(c)
proc toUpper*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} =
proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
## Converts `c` into upper case. This works for any Unicode character.
## If possible, prefer `toLower` over `toUpper`.
var c = IRune(c)
var c = RuneImpl(c)
var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
if p >= 0 and c >= toupperRanges[p] and c <= toupperRanges[p+1]:
return TRune(c + toupperRanges[p+2] - 500)
return Rune(c + toupperRanges[p+2] - 500)
p = binarySearch(c, toupperSinglets, len(toupperSinglets) div 2, 2)
if p >= 0 and c == toupperSinglets[p]:
return TRune(c + toupperSinglets[p+1] - 500)
return TRune(c)
return Rune(c + toupperSinglets[p+1] - 500)
return Rune(c)
proc toTitle*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} =
var c = IRune(c)
proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
var c = RuneImpl(c)
var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
if p >= 0 and c == toTitleSinglets[p]:
return TRune(c + toTitleSinglets[p+1] - 500)
return TRune(c)
return Rune(c + toTitleSinglets[p+1] - 500)
return Rune(c)
proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is a lower case Unicode character
## If possible, prefer `isLower` over `isUpper`.
var c = IRune(c)
var c = RuneImpl(c)
# Note: toUpperRanges is correct here!
var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
if p >= 0 and c >= toupperRanges[p] and c <= toupperRanges[p+1]:
@ -1158,10 +1160,10 @@ proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
if p >= 0 and c == toupperSinglets[p]:
return true
proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is a upper case Unicode character
## If possible, prefer `isLower` over `isUpper`.
var c = IRune(c)
var c = RuneImpl(c)
# Note: toLowerRanges is correct here!
var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]:
@ -1170,11 +1172,11 @@ proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
if p >= 0 and c == tolowerSinglets[p]:
return true
proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
if isUpper(c) or isLower(c):
return true
var c = IRune(c)
var c = RuneImpl(c)
var p = binarySearch(c, alphaRanges, len(alphaRanges) div 2, 2)
if p >= 0 and c >= alphaRanges[p] and c <= alphaRanges[p+1]:
return true
@ -1182,21 +1184,21 @@ proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
if p >= 0 and c == alphaSinglets[p]:
return true
proc isTitle*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
return isUpper(c) and isLower(c)
proc isWhiteSpace*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is a Unicode whitespace character
var c = IRune(c)
var c = RuneImpl(c)
var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]:
return true
iterator runes*(s: string): TRune =
iterator runes*(s: string): Rune =
## iterates over any unicode character of the string `s`.
var
i = 0
result: TRune
result: Rune
while i < len(s):
fastRuneAt(s, i, result, true)
yield result
@ -1209,12 +1211,12 @@ proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} =
## | > 0 iff a > b
var i = 0
var j = 0
var ar, br: TRune
var ar, br: Rune
while i < a.len and j < b.len:
# slow path:
fastRuneAt(a, i, ar)
fastRuneAt(b, j, br)
result = IRune(toLower(ar)) - IRune(toLower(br))
result = RuneImpl(toLower(ar)) - RuneImpl(toLower(br))
if result != 0: return
result = a.len - b.len

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -55,7 +55,7 @@ proc unidecode*(s: string): string =
##
## Example:
##
## ..code-block:: nimrod
## ..code-block:: nim
##
## unidecode("\x53\x17\x4E\xB0")
##

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Nimrod Contributors
#
# See the file "copying.txt", included in this
@ -26,16 +26,19 @@ when not defined(ECMAScript):
import terminal
type
TTestStatus* = enum OK, FAILED
TOutputLevel* = enum PRINT_ALL, PRINT_FAILURES, PRINT_NONE
TestStatus* = enum OK, FAILED
OutputLevel* = enum PRINT_ALL, PRINT_FAILURES, PRINT_NONE
{.deprecated: [TTestStatus: TestStatus, TOutputLevel: OutputLevel]}
var
# XXX: These better be thread-local
AbortOnError*: bool
OutputLevel*: TOutputLevel
ColorOutput*: bool
abortOnError* {.threadvar.}: bool
outputLevel* {.threadvar.}: OutputLevel
colorOutput* {.threadvar.}: bool
checkpoints: seq[string] = @[]
checkpoints {.threadvar.}: seq[string]
checkpoints = @[]
template TestSetupIMPL*: stmt {.immediate, dirty.} = discard
template TestTeardownIMPL*: stmt {.immediate, dirty.} = discard
@ -53,7 +56,7 @@ template suite*(name: expr, body: stmt): stmt {.immediate, dirty.} =
body
proc testDone(name: string, s: TTestStatus) =
proc testDone(name: string, s: TestStatus) =
if s == FAILED:
program_result += 1
@ -192,15 +195,15 @@ when declared(stdout):
## Reading settings
var envOutLvl = os.getEnv("NIMTEST_OUTPUT_LVL").string
AbortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR")
ColorOutput = not existsEnv("NIMTEST_NO_COLOR")
abortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR")
colorOutput = not existsEnv("NIMTEST_NO_COLOR")
else:
var envOutLvl = "" # TODO
ColorOutput = false
colorOutput = false
if envOutLvl.len > 0:
for opt in countup(low(TOutputLevel), high(TOutputLevel)):
for opt in countup(low(OutputLevel), high(OutputLevel)):
if $opt == envOutLvl:
OutputLevel = opt
outputLevel = opt
break

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2014 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -11,12 +11,14 @@
import strutils, parseutils
type
TUrl* = distinct string
Url* = distinct string
TUri* = object
Uri* = object
scheme*, username*, password*: string
hostname*, port*, path*, query*, anchor*: string
{.deprecated: [TUrl: Url, TUri: Uri].}
proc `$`*(url: TUrl): string {.deprecated.} =
## **Deprecated since 0.9.6**: Use ``TUri`` instead.
return string(url)
@ -172,7 +174,7 @@ proc combine*(base: TUri, reference: TUri): TUri =
##
## Examples:
##
## .. code-block:: nimrod
## .. code-block::
## let foo = combine(parseUri("http://example.com/foo/bar"), parseUri("/baz"))
## assert foo.path == "/baz"
##
@ -229,7 +231,7 @@ proc `/`*(x: TUri, path: string): TUri =
##
## Examples:
##
## .. code-block:: nimrod
## .. code-block::
## let foo = parseUri("http://example.com/foo/bar") / parseUri("/baz")
## assert foo.path == "/foo/bar/baz"
##

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2010 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -9,7 +9,8 @@
import strutils
## This module implements XML DOM Level 2 Core specification(http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html)
## This module implements XML DOM Level 2 Core
## specification (http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html)
#http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2010 Dominik Picheta
#
# See the file "copying.txt", included in this
@ -156,7 +156,7 @@ proc loadXMLFile*(path: string): PDocument =
when isMainModule:
var xml = loadXMLFile(r"C:\Users\Dominik\Desktop\Code\Nimrod\xmldom\test.xml")
var xml = loadXMLFile("nim/xmldom/test.xml")
#echo(xml.getElementsByTagName("m:test2")[0].namespaceURI)
#echo(xml.getElementsByTagName("bla:test")[0].namespaceURI)
#echo(xml.getElementsByTagName("test")[0].namespaceURI)

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -12,9 +12,11 @@
import streams, parsexml, strtabs, xmltree
type
EInvalidXml* = object of EInvalidValue ## exception that is raised
## for invalid XML
errors*: seq[string] ## all detected parsing errors
XmlError* = object of ValueError ## exception that is raised
## for invalid XML
errors*: seq[string] ## all detected parsing errors
{.deprecated: [EInvalidXml: XmlError].}
proc raiseInvalidXml(errors: seq[string]) =
var e: ref EInvalidXml
@ -23,12 +25,12 @@ proc raiseInvalidXml(errors: seq[string]) =
e.errors = errors
raise e
proc addNode(father, son: PXmlNode) =
proc addNode(father, son: XmlNode) =
if son != nil: add(father, son)
proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode
proc parse(x: var XmlParser, errors: var seq[string]): XmlNode
proc untilElementEnd(x: var TXmlParser, result: PXmlNode,
proc untilElementEnd(x: var XmlParser, result: XmlNode,
errors: var seq[string]) =
while true:
case x.kind
@ -45,7 +47,7 @@ proc untilElementEnd(x: var TXmlParser, result: PXmlNode,
else:
result.addNode(parse(x, errors))
proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode =
proc parse(x: var XmlParser, errors: var seq[string]): XmlNode =
case x.kind
of xmlComment:
result = newComment(x.charData)
@ -98,11 +100,11 @@ proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode =
next(x)
of xmlEof: discard
proc parseXml*(s: PStream, filename: string,
errors: var seq[string]): PXmlNode =
proc parseXml*(s: Stream, filename: string,
errors: var seq[string]): XmlNode =
## parses the XML from stream `s` and returns a ``PXmlNode``. Every
## occured parsing error is added to the `errors` sequence.
var x: TXmlParser
var x: XmlParser
open(x, s, filename, {reportComments})
while true:
x.next()
@ -118,14 +120,14 @@ proc parseXml*(s: PStream, filename: string,
break
close(x)
proc parseXml*(s: PStream): PXmlNode =
proc parseXml*(s: Stream): XmlNode =
## parses the XTML from stream `s` and returns a ``PXmlNode``. All parsing
## errors are turned into an ``EInvalidXML`` exception.
var errors: seq[string] = @[]
result = parseXml(s, "unknown_html_doc", errors)
if errors.len > 0: raiseInvalidXMl(errors)
proc loadXml*(path: string, errors: var seq[string]): PXmlNode =
proc loadXml*(path: string, errors: var seq[string]): XmlNode =
## Loads and parses XML from file specified by ``path``, and returns
## a ``PXmlNode``. Every occured parsing error is added to the `errors`
## sequence.
@ -133,7 +135,7 @@ proc loadXml*(path: string, errors: var seq[string]): PXmlNode =
if s == nil: raise newException(EIO, "Unable to read file: " & path)
result = parseXml(s, path, errors)
proc loadXml*(path: string): PXmlNode =
proc loadXml*(path: string): XmlNode =
## Loads and parses XML from file specified by ``path``, and returns
## a ``PXmlNode``. All parsing errors are turned into an ``EInvalidXML``
## exception.
@ -148,7 +150,7 @@ when isMainModule:
var x = loadXml(paramStr(1), errors)
for e in items(errors): echo e
var f: TFile
var f: File
if open(f, "xmltest.txt", fmWrite):
f.write($x)
f.close()

View file

@ -1,6 +1,6 @@
#
#
# Nimrod's Runtime Library
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -12,33 +12,36 @@
import macros, strtabs
type
PXmlNode* = ref TXmlNode ## an XML tree consists of ``PXmlNode``'s.
XmlNode* = ref TXmlNode ## an XML tree consists of ``PXmlNode``'s.
TXmlNodeKind* = enum ## different kinds of ``PXmlNode``'s
XmlNodeKind* = enum ## different kinds of ``PXmlNode``'s
xnText, ## a text element
xnElement, ## an element with 0 or more children
xnCData, ## a CDATA node
xnEntity, ## an entity (like ``&thing;``)
xnComment ## an XML comment
PXmlAttributes* = PStringTable ## an alias for a string to string mapping
XmlAttributes* = StringTableRef ## an alias for a string to string mapping
TXmlNode {.pure, final, acyclic.} = object
case k: TXmlNodeKind # private, use the kind() proc to read this field.
XmlNodeObj {.acyclic.} = object
case k: XmlNodeKind # private, use the kind() proc to read this field.
of xnText, xnComment, xnCData, xnEntity:
fText: string
of xnElement:
fTag: string
s: seq[PXmlNode]
fAttr: PXmlAttributes
s: seq[XmlNode]
fAttr: XmlAttributes
fClientData: int ## for other clients
proc newXmlNode(kind: TXmlNodeKind): PXmlNode =
## creates a new ``PXmlNode``.
{.deprecated: [PXmlNode: XmlNode, TXmlNodeKind: XmlNodeKind, PXmlAttributes:
XmlAttributes, TXmlNode: XmlNodeObj].}
proc newXmlNode(kind: XmlNodeKind): XmlNode =
## creates a new ``XmlNode``.
new(result)
result.k = kind
proc newElement*(tag: string): PXmlNode =
proc newElement*(tag: string): XmlNode =
## creates a new ``PXmlNode`` of kind ``xnText`` with the given `tag`.
result = newXmlNode(xnElement)
result.fTag = tag
@ -304,10 +307,10 @@ proc findAll*(n: PXmlNode, tag: string, result: var seq[PXmlNode]) =
## Found nodes satisfying the condition will be appended to the `result`
## sequence, which can't be nil or the proc will crash. Usage example:
##
## .. code-block:: nimrod
## .. code-block::
## var
## html: PXmlNode
## tags: seq[PXmlNode] = @[]
## html: XmlNode
## tags: seq[XmlNode] = @[]
##
## html = buildHtml()
## findAll(html, "img", tags)
@ -326,8 +329,8 @@ proc findAll*(n: PXmlNode, tag: string, result: var seq[PXmlNode]) =
proc findAll*(n: PXmlNode, tag: string): seq[PXmlNode] =
## Shortcut version to assign in let blocks. Example:
##
## .. code-block:: nimrod
## var html: PXmlNode
## .. code-block::
## var html: XmlNode
##
## html = buildHtml(html)
## for imgTag in html.findAll("img"):

View file

@ -2437,6 +2437,8 @@ when not defined(JS): #and not defined(NimrodVM):
## returns the OS file handle of the file ``f``. This is only useful for
## platform specific programming.
{.deprecated: [fileHandle: getFileHandle].}
proc cstringArrayToSeq*(a: cstringArray, len: int): seq[string] =
## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
## of length ``len``.