mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 05:50:30 +00:00
fixed minor bugs; cleaned up tests
This commit is contained in:
@@ -859,7 +859,8 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||
if s.typ.lockLevel == UnspecifiedLockLevel:
|
||||
s.typ.lockLevel = t.maxLockLevel
|
||||
elif t.maxLockLevel > s.typ.lockLevel:
|
||||
localError(s.info,
|
||||
#localError(s.info,
|
||||
message(s.info, warnLockLevel,
|
||||
"declared lock level is $1, but real lock level is $2" %
|
||||
[$s.typ.lockLevel, $t.maxLockLevel])
|
||||
|
||||
|
||||
@@ -136,12 +136,12 @@ proc len*(n: PNimrodNode): int {.magic: "NLen", noSideEffect.}
|
||||
## returns the number of children of `n`.
|
||||
|
||||
proc add*(father, child: PNimrodNode): PNimrodNode {.magic: "NAdd", discardable,
|
||||
noSideEffect.}
|
||||
noSideEffect, locks: 0.}
|
||||
## Adds the `child` to the `father` node. Returns the
|
||||
## father node so that calls can be nested.
|
||||
|
||||
proc add*(father: PNimrodNode, children: varargs[PNimrodNode]): PNimrodNode {.
|
||||
magic: "NAddMultiple", discardable, noSideEffect.}
|
||||
magic: "NAddMultiple", discardable, noSideEffect, locks: 0.}
|
||||
## Adds each child of `children` to the `father` node.
|
||||
## Returns the `father` node so that calls can be nested.
|
||||
|
||||
@@ -177,13 +177,13 @@ proc newNimNode*(kind: TNimrodNodeKind,
|
||||
proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode", noSideEffect.}
|
||||
proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree", noSideEffect.}
|
||||
|
||||
proc error*(msg: string) {.magic: "NError", gcsafe.}
|
||||
proc error*(msg: string) {.magic: "NError", benign.}
|
||||
## writes an error message at compile time
|
||||
|
||||
proc warning*(msg: string) {.magic: "NWarning", gcsafe.}
|
||||
proc warning*(msg: string) {.magic: "NWarning", benign.}
|
||||
## writes a warning message at compile time
|
||||
|
||||
proc hint*(msg: string) {.magic: "NHint", gcsafe.}
|
||||
proc hint*(msg: string) {.magic: "NHint", benign.}
|
||||
## writes a hint message at compile time
|
||||
|
||||
proc newStrLitNode*(s: string): PNimrodNode {.compileTime, noSideEffect.} =
|
||||
@@ -237,7 +237,7 @@ proc genSym*(kind: TNimrodSymKind = nskLet; ident = ""): PNimrodNode {.
|
||||
## generates a fresh symbol that is guaranteed to be unique. The symbol
|
||||
## needs to occur in a declaration context.
|
||||
|
||||
proc callsite*(): PNimrodNode {.magic: "NCallSite", gcsafe.}
|
||||
proc callsite*(): PNimrodNode {.magic: "NCallSite", benign.}
|
||||
## returns the AST of the invocation expression that invoked this macro.
|
||||
|
||||
proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||
@@ -387,11 +387,11 @@ proc nestList*(theProc: TNimrodIdent,
|
||||
# This could easily user code and so should be fixed in evals.nim somehow.
|
||||
result = newCall(theProc, x[i], copyNimTree(result))
|
||||
|
||||
proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
|
||||
proc treeRepr*(n: PNimrodNode): string {.compileTime, benign.} =
|
||||
## Convert the AST `n` to a human-readable tree-like string.
|
||||
##
|
||||
## See also `repr` and `lispRepr`.
|
||||
proc traverse(res: var string, level: int, n: PNimrodNode) =
|
||||
proc traverse(res: var string, level: int, n: PNimrodNode) {.benign.} =
|
||||
for i in 0..level-1: res.add " "
|
||||
res.add(($n.kind).substr(3))
|
||||
|
||||
@@ -412,7 +412,7 @@ proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
|
||||
result = ""
|
||||
traverse(result, 0, n)
|
||||
|
||||
proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
|
||||
proc lispRepr*(n: PNimrodNode): string {.compileTime, benign.} =
|
||||
## Convert the AST `n` to a human-readable lisp-like string,
|
||||
##
|
||||
## See also `repr` and `treeRepr`.
|
||||
@@ -651,7 +651,7 @@ proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} =
|
||||
else:
|
||||
badNodeKind someProc.kind, "body="
|
||||
|
||||
proc basename*(a: PNimrodNode): PNimrodNode {.compiletime.}
|
||||
proc basename*(a: PNimrodNode): PNimrodNode {.compiletime, benign.}
|
||||
|
||||
|
||||
proc `$`*(node: PNimrodNode): string {.compileTime.} =
|
||||
|
||||
@@ -347,7 +347,7 @@ proc `$`*[A, B](t: TableRef[A, B]): string =
|
||||
proc `==`*[A, B](s, t: TableRef[A, B]): bool =
|
||||
if isNil(s): result = isNil(t)
|
||||
elif isNil(t): result = false
|
||||
else: result = equalsImpl()
|
||||
else: equalsImpl()
|
||||
|
||||
proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] =
|
||||
## Index the collection with the proc provided.
|
||||
|
||||
@@ -129,25 +129,25 @@ proc variance*(x: openArray[float]): float {.noSideEffect.} =
|
||||
result = result + diff*diff
|
||||
result = result / toFloat(len(x))
|
||||
|
||||
proc random*(max: int): int {.gcsafe.}
|
||||
proc random*(max: int): int {.benign.}
|
||||
## returns a random number in the range 0..max-1. The sequence of
|
||||
## random number is always the same, unless `randomize` is called
|
||||
## which initializes the random number generator with a "random"
|
||||
## number, i.e. a tickcount.
|
||||
|
||||
proc random*(max: float): float {.gcsafe.}
|
||||
proc random*(max: float): float {.benign.}
|
||||
## returns a random number in the range 0..<max. The sequence of
|
||||
## random number is always the same, unless `randomize` is called
|
||||
## which initializes the random number generator with a "random"
|
||||
## number, i.e. a tickcount. This has a 16-bit resolution on windows
|
||||
## and a 48-bit resolution on other platforms.
|
||||
|
||||
proc randomize*() {.gcsafe.}
|
||||
proc randomize*() {.benign.}
|
||||
## initializes the random number generator with a "random"
|
||||
## number, i.e. a tickcount. Note: Does nothing for the JavaScript target,
|
||||
## as JavaScript does not support this.
|
||||
|
||||
proc randomize*(seed: int) {.gcsafe.}
|
||||
proc randomize*(seed: int) {.benign.}
|
||||
## initializes the random number generator with a specific seed.
|
||||
## Note: Does nothing for the JavaScript target,
|
||||
## as JavaScript does not support this.
|
||||
|
||||
@@ -321,7 +321,8 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
|
||||
dealloc(aiList)
|
||||
|
||||
proc acceptAddr*(server: Socket, client: var Socket, address: var string,
|
||||
flags = {SocketFlag.SafeDisconn}) {.tags: [ReadIOEffect].} =
|
||||
flags = {SocketFlag.SafeDisconn}) {.
|
||||
tags: [ReadIOEffect], gcsafe, locks: 0.} =
|
||||
## Blocks until a connection is being made from a client. When a connection
|
||||
## is made sets ``client`` to the client socket and ``address`` to the address
|
||||
## of the connecting client.
|
||||
@@ -938,8 +939,12 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
|
||||
doAssert socket.handshake()
|
||||
socket.fd.setBlocking(true)
|
||||
|
||||
proc isSsl*(socket: Socket): bool = return socket.isSSL
|
||||
proc isSsl*(socket: Socket): bool =
|
||||
## Determines whether ``socket`` is a SSL socket.
|
||||
when defined(ssl):
|
||||
result = socket.isSSL
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc getFd*(socket: Socket): SocketHandle = return socket.fd
|
||||
## Returns the socket's file descriptor
|
||||
|
||||
@@ -1339,7 +1339,7 @@ proc rawRemoveDir(dir: string) =
|
||||
if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError())
|
||||
|
||||
proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
|
||||
WriteDirEffect, ReadDirEffect].} =
|
||||
WriteDirEffect, ReadDirEffect], benign.} =
|
||||
## Removes the directory `dir` including all subdirectories and files
|
||||
## in `dir` (recursively).
|
||||
##
|
||||
@@ -1385,7 +1385,7 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
|
||||
rawCreateDir(dir)
|
||||
|
||||
proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
tags: [WriteIOEffect, ReadIOEffect].} =
|
||||
tags: [WriteIOEffect, ReadIOEffect], benign.} =
|
||||
## Copies a directory from `source` to `dest`.
|
||||
##
|
||||
## If this fails, `OSError` is raised. On the Windows platform this proc will
|
||||
@@ -1558,7 +1558,7 @@ proc copyFileWithPermissions*(source, dest: string,
|
||||
|
||||
proc copyDirWithPermissions*(source, dest: string,
|
||||
ignorePermissionErrors = true) {.rtl, extern: "nos$1",
|
||||
tags: [WriteIOEffect, ReadIOEffect].} =
|
||||
tags: [WriteIOEffect, ReadIOEffect], benign.} =
|
||||
## Copies a directory from `source` to `dest` preserving file permissions.
|
||||
##
|
||||
## If this fails, `OSError` is raised. This is a wrapper proc around `copyDir()
|
||||
|
||||
@@ -63,44 +63,44 @@ elif defined(windows):
|
||||
elif defined(JS):
|
||||
type
|
||||
Time* {.importc.} = object
|
||||
getDay: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getFullYear: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getHours: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getMilliseconds: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getMinutes: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getMonth: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getSeconds: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getTime: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getTimezoneOffset: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getDate: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getUTCDate: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getUTCFullYear: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getUTCHours: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getUTCMilliseconds: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getUTCMinutes: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getUTCMonth: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getUTCSeconds: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getUTCDay: proc (): int {.tags: [], raises: [], gcsafe.}
|
||||
getYear: proc (): int {.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.}
|
||||
setMilliseconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
||||
setMinutes: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
||||
setMonth: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
||||
setSeconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
||||
setTime: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
||||
setUTCDate: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
||||
setUTCFullYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
||||
setUTCHours: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
||||
setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
||||
setUTCMinutes: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
||||
setUTCMonth: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
||||
setUTCSeconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
||||
setYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
|
||||
toGMTString: proc (): cstring {.tags: [], raises: [], gcsafe.}
|
||||
toLocaleString: proc (): cstring {.tags: [], raises: [], gcsafe.}
|
||||
getDay: proc (): int {.tags: [], raises: [], benign.}
|
||||
getFullYear: proc (): int {.tags: [], raises: [], benign.}
|
||||
getHours: proc (): int {.tags: [], raises: [], benign.}
|
||||
getMilliseconds: proc (): int {.tags: [], raises: [], benign.}
|
||||
getMinutes: proc (): int {.tags: [], raises: [], benign.}
|
||||
getMonth: proc (): int {.tags: [], raises: [], benign.}
|
||||
getSeconds: proc (): int {.tags: [], raises: [], benign.}
|
||||
getTime: proc (): int {.tags: [], raises: [], benign.}
|
||||
getTimezoneOffset: proc (): int {.tags: [], raises: [], benign.}
|
||||
getDate: proc (): int {.tags: [], raises: [], benign.}
|
||||
getUTCDate: proc (): int {.tags: [], raises: [], benign.}
|
||||
getUTCFullYear: proc (): int {.tags: [], raises: [], benign.}
|
||||
getUTCHours: proc (): int {.tags: [], raises: [], benign.}
|
||||
getUTCMilliseconds: proc (): int {.tags: [], raises: [], benign.}
|
||||
getUTCMinutes: proc (): int {.tags: [], raises: [], benign.}
|
||||
getUTCMonth: proc (): int {.tags: [], raises: [], benign.}
|
||||
getUTCSeconds: proc (): int {.tags: [], raises: [], benign.}
|
||||
getUTCDay: proc (): int {.tags: [], raises: [], benign.}
|
||||
getYear: proc (): int {.tags: [], raises: [], benign.}
|
||||
parse: proc (s: cstring): Time {.tags: [], raises: [], benign.}
|
||||
setDate: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setFullYear: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setHours: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setMinutes: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setMonth: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setSeconds: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setTime: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setUTCDate: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setUTCFullYear: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setUTCHours: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setUTCMinutes: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setUTCMonth: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setUTCSeconds: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
setYear: proc (x: int) {.tags: [], raises: [], benign.}
|
||||
toGMTString: proc (): cstring {.tags: [], raises: [], benign.}
|
||||
toLocaleString: proc (): cstring {.tags: [], raises: [], benign.}
|
||||
|
||||
type
|
||||
TimeInfo* = object of RootObj ## represents a time in different parts
|
||||
@@ -139,42 +139,42 @@ type
|
||||
{.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
|
||||
TTimeInterval: TimeInterval, TTimeInfo: TimeInfo].}
|
||||
|
||||
proc getTime*(): Time {.tags: [TimeEffect], gcsafe.}
|
||||
proc getTime*(): Time {.tags: [TimeEffect], benign.}
|
||||
## 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: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.}
|
||||
proc getLocalTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.}
|
||||
## converts the calendar time `t` to broken-time representation,
|
||||
## expressed relative to the user's specified time zone.
|
||||
proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.}
|
||||
proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.}
|
||||
## converts the calendar time `t` to broken-down time representation,
|
||||
## expressed in Coordinated Universal Time (UTC).
|
||||
|
||||
proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], gcsafe.}
|
||||
proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign.}
|
||||
## converts a broken-down time structure to
|
||||
## calendar time representation. The function ignores the specified
|
||||
## contents of the structure members `weekday` and `yearday` and recomputes
|
||||
## them from the other information in the broken-down time structure.
|
||||
|
||||
proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], gcsafe.}
|
||||
proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], benign.}
|
||||
## Takes a float which contains the number of seconds since the unix epoch and
|
||||
## returns a time object.
|
||||
|
||||
proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], gcsafe.} =
|
||||
proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign.} =
|
||||
## Takes an int which contains the number of seconds since the unix epoch and
|
||||
## returns a time object.
|
||||
fromSeconds(float(since1970))
|
||||
|
||||
proc toSeconds*(time: Time): float {.tags: [], raises: [], gcsafe.}
|
||||
proc toSeconds*(time: Time): float {.tags: [], raises: [], benign.}
|
||||
## Returns the time in seconds since the unix epoch.
|
||||
|
||||
proc `$` *(timeInfo: TimeInfo): string {.tags: [], raises: [], gcsafe.}
|
||||
proc `$` *(timeInfo: TimeInfo): string {.tags: [], raises: [], benign.}
|
||||
## converts a `TimeInfo` object to a string representation.
|
||||
proc `$` *(time: Time): string {.tags: [], raises: [], gcsafe.}
|
||||
proc `$` *(time: Time): string {.tags: [], raises: [], benign.}
|
||||
## converts a calendar time to a string representation.
|
||||
|
||||
proc `-`*(a, b: Time): int64 {.
|
||||
rtl, extern: "ntDiffTime", tags: [], raises: [].}
|
||||
rtl, extern: "ntDiffTime", tags: [], raises: [], benign.}
|
||||
## computes the difference of two calendar times. Result is in seconds.
|
||||
|
||||
proc `<`*(a, b: Time): bool {.
|
||||
@@ -194,14 +194,14 @@ proc `==`*(a, b: Time): bool {.
|
||||
|
||||
when not defined(JS):
|
||||
proc getTzname*(): tuple[nonDST, DST: string] {.tags: [TimeEffect], raises: [],
|
||||
gcsafe.}
|
||||
benign.}
|
||||
## returns the local timezone; ``nonDST`` is the name of the local non-DST
|
||||
## timezone, ``DST`` is the name of the local DST timezone.
|
||||
|
||||
proc getTimezone*(): int {.tags: [TimeEffect], raises: [], gcsafe.}
|
||||
proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign.}
|
||||
## returns the offset of the local (non-DST) timezone in seconds west of UTC.
|
||||
|
||||
proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], gcsafe.}
|
||||
proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.}
|
||||
## get the miliseconds from the start of the program. **Deprecated since
|
||||
## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
|
||||
|
||||
|
||||
@@ -2098,17 +2098,16 @@ when not defined(nimrodVM) and hostOS != "standalone":
|
||||
## returns an informative string about the GC's activity. This may be useful
|
||||
## for tweaking.
|
||||
|
||||
# XXX mark these as 'locks: 0' once 0.10.0 has been released
|
||||
proc GC_ref*[T](x: ref T) {.magic: "GCref", gcsafe.}
|
||||
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", gcsafe.}
|
||||
proc GC_ref*(x: string) {.magic: "GCref", gcsafe.}
|
||||
proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
|
||||
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
|
||||
proc GC_ref*(x: string) {.magic: "GCref", benign.}
|
||||
## marks the object `x` as referenced, so that it will not be freed until
|
||||
## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
|
||||
## n calls to `GC_unref` are needed to unmark `x`.
|
||||
|
||||
proc GC_unref*[T](x: ref T) {.magic: "GCunref", gcsafe.}
|
||||
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", gcsafe.}
|
||||
proc GC_unref*(x: string) {.magic: "GCunref", gcsafe.}
|
||||
proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
|
||||
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
|
||||
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
|
||||
## see the documentation of `GC_ref`.
|
||||
|
||||
template accumulateResult*(iter: expr) =
|
||||
@@ -2248,14 +2247,9 @@ when not declared(sysFatal):
|
||||
e.msg = message & arg
|
||||
raise e
|
||||
|
||||
when defined(nimlocks):
|
||||
proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe, locks: 0.}
|
||||
## get type information for `x`. Ordinary code should not use this, but
|
||||
## the `typeinfo` module instead.
|
||||
else:
|
||||
proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe.}
|
||||
## get type information for `x`. Ordinary code should not use this, but
|
||||
## the `typeinfo` module instead.
|
||||
proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.}
|
||||
## get type information for `x`. Ordinary code should not use this, but
|
||||
## the `typeinfo` module instead.
|
||||
|
||||
{.push stackTrace: off.}
|
||||
proc abs*(x: int): int {.magic: "AbsI", noSideEffect.} =
|
||||
@@ -2455,14 +2449,10 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||
## Returns ``false`` if the end of the file has been reached, ``true``
|
||||
## otherwise. If ``false`` is returned `line` contains no new data.
|
||||
|
||||
when not defined(booting):
|
||||
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
|
||||
tags: [WriteIOEffect], gcsafe, locks: 0.}
|
||||
## writes the values `x` to `f` and then writes "\n".
|
||||
## May throw an IO exception.
|
||||
else:
|
||||
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
|
||||
tags: [WriteIOEffect].}
|
||||
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
|
||||
tags: [WriteIOEffect], benign.}
|
||||
## writes the values `x` to `f` and then writes "\n".
|
||||
## May throw an IO exception.
|
||||
|
||||
proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
|
||||
## retrieves the file size (in bytes) of `f`.
|
||||
@@ -2576,7 +2566,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||
initAllocator()
|
||||
when hasThreadSupport:
|
||||
include "system/syslocks"
|
||||
include "system/threads"
|
||||
when hostOS != "standalone": include "system/threads"
|
||||
elif not defined(nogc) and not defined(NimrodVM) and hostOS != "standalone":
|
||||
when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom()
|
||||
initGC()
|
||||
|
||||
@@ -78,7 +78,7 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
|
||||
type
|
||||
PByteArray = ptr array[0.. 0xffff, int8]
|
||||
|
||||
proc addSetElem(result: var string, elem: int, typ: PNimType) {.gcsafe.} =
|
||||
proc addSetElem(result: var string, elem: int, typ: PNimType) {.benign.} =
|
||||
case typ.kind
|
||||
of tyEnum: add result, reprEnum(elem, typ)
|
||||
of tyBool: add result, reprBool(bool(elem))
|
||||
@@ -147,7 +147,7 @@ when not defined(useNimRtl):
|
||||
for i in 0..cl.indent-1: add result, ' '
|
||||
|
||||
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
||||
cl: var TReprClosure) {.gcsafe.}
|
||||
cl: var TReprClosure) {.benign.}
|
||||
|
||||
proc reprArray(result: var string, p: pointer, typ: PNimType,
|
||||
cl: var TReprClosure) =
|
||||
@@ -172,7 +172,7 @@ when not defined(useNimRtl):
|
||||
add result, "]"
|
||||
|
||||
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
|
||||
cl: var TReprClosure) {.gcsafe.} =
|
||||
cl: var TReprClosure) {.benign.} =
|
||||
case n.kind
|
||||
of nkNone: sysAssert(false, "reprRecordAux")
|
||||
of nkSlot:
|
||||
|
||||
22
tests/collections/tindexby.nim
Normal file
22
tests/collections/tindexby.nim
Normal file
@@ -0,0 +1,22 @@
|
||||
import tables
|
||||
|
||||
doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table"
|
||||
|
||||
var tbl1 = initTable[int, int]()
|
||||
tbl1.add(1,1)
|
||||
tbl1.add(2,2)
|
||||
doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table"
|
||||
|
||||
type
|
||||
TElem = object
|
||||
foo: int
|
||||
bar: string
|
||||
|
||||
let
|
||||
elem1 = TElem(foo: 1, bar: "bar")
|
||||
elem2 = TElem(foo: 2, bar: "baz")
|
||||
|
||||
var tbl2 = initTable[string, TElem]()
|
||||
tbl2.add("bar", elem1)
|
||||
tbl2.add("baz", elem2)
|
||||
doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"
|
||||
@@ -1,22 +1,128 @@
|
||||
import tables
|
||||
discard """
|
||||
output: '''true'''
|
||||
"""
|
||||
|
||||
doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table"
|
||||
import hashes, tables
|
||||
|
||||
var tbl1 = initTable[int, int]()
|
||||
tbl1.add(1,1)
|
||||
tbl1.add(2,2)
|
||||
doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table"
|
||||
const
|
||||
data = {
|
||||
"34": 123456, "12": 789,
|
||||
"90": 343, "0": 34404,
|
||||
"1": 344004, "2": 344774,
|
||||
"3": 342244, "4": 3412344,
|
||||
"5": 341232144, "6": 34214544,
|
||||
"7": 3434544, "8": 344544,
|
||||
"9": 34435644, "---00": 346677844,
|
||||
"10": 34484, "11": 34474, "19": 34464,
|
||||
"20": 34454, "30": 34141244, "40": 344114,
|
||||
"50": 344490, "60": 344491, "70": 344492,
|
||||
"80": 344497}
|
||||
|
||||
type
|
||||
TElem = object
|
||||
foo: int
|
||||
bar: string
|
||||
|
||||
let
|
||||
elem1 = TElem(foo: 1, bar: "bar")
|
||||
elem2 = TElem(foo: 2, bar: "baz")
|
||||
sorteddata = {
|
||||
"---00": 346677844,
|
||||
"0": 34404,
|
||||
"1": 344004,
|
||||
"10": 34484,
|
||||
"11": 34474,
|
||||
"12": 789,
|
||||
"19": 34464,
|
||||
"2": 344774, "20": 34454,
|
||||
"3": 342244, "30": 34141244,
|
||||
"34": 123456,
|
||||
"4": 3412344, "40": 344114,
|
||||
"5": 341232144, "50": 344490,
|
||||
"6": 34214544, "60": 344491,
|
||||
"7": 3434544, "70": 344492,
|
||||
"8": 344544, "80": 344497,
|
||||
"9": 34435644,
|
||||
"90": 343}
|
||||
|
||||
block tableTest1:
|
||||
var t = initTable[tuple[x, y: int], string]()
|
||||
t[(0,0)] = "00"
|
||||
t[(1,0)] = "10"
|
||||
t[(0,1)] = "01"
|
||||
t[(1,1)] = "11"
|
||||
for x in 0..1:
|
||||
for y in 0..1:
|
||||
assert t[(x,y)] == $x & $y
|
||||
assert($t ==
|
||||
"{(x: 0, y: 0): 00, (x: 0, y: 1): 01, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
|
||||
|
||||
block tableTest2:
|
||||
var t = initTable[string, float]()
|
||||
t["test"] = 1.2345
|
||||
t["111"] = 1.000043
|
||||
t["123"] = 1.23
|
||||
t.del("111")
|
||||
|
||||
var tbl2 = initTable[string, TElem]()
|
||||
tbl2.add("bar", elem1)
|
||||
tbl2.add("baz", elem2)
|
||||
doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"
|
||||
t["012"] = 67.9
|
||||
t["123"] = 1.5 # test overwriting
|
||||
|
||||
assert t["123"] == 1.5
|
||||
assert t["111"] == 0.0 # deleted
|
||||
assert(not hasKey(t, "111"))
|
||||
|
||||
for key, val in items(data): t[key] = val.toFloat
|
||||
for key, val in items(data): assert t[key] == val.toFloat
|
||||
|
||||
|
||||
block orderedTableTest1:
|
||||
var t = initOrderedTable[string, int](2)
|
||||
for key, val in items(data): t[key] = val
|
||||
for key, val in items(data): assert t[key] == val
|
||||
var i = 0
|
||||
# `pairs` needs to yield in insertion order:
|
||||
for key, val in pairs(t):
|
||||
assert key == data[i][0]
|
||||
assert val == data[i][1]
|
||||
inc(i)
|
||||
|
||||
for key, val in mpairs(t): val = 99
|
||||
for val in mvalues(t): assert val == 99
|
||||
|
||||
block countTableTest1:
|
||||
var s = data.toTable
|
||||
var t = initCountTable[string]()
|
||||
for k in s.keys: t.inc(k)
|
||||
for k in t.keys: assert t[k] == 1
|
||||
t.inc("90", 3)
|
||||
t.inc("12", 2)
|
||||
t.inc("34", 1)
|
||||
assert t.largest()[0] == "90"
|
||||
|
||||
t.sort()
|
||||
var i = 0
|
||||
for k, v in t.pairs:
|
||||
case i
|
||||
of 0: assert k == "90" and v == 4
|
||||
of 1: assert k == "12" and v == 3
|
||||
of 2: assert k == "34" and v == 2
|
||||
else: break
|
||||
inc i
|
||||
|
||||
block SyntaxTest:
|
||||
var x = toTable[int, string]({:})
|
||||
|
||||
proc orderedTableSortTest() =
|
||||
var t = initOrderedTable[string, int](2)
|
||||
for key, val in items(data): t[key] = val
|
||||
for key, val in items(data): assert t[key] == val
|
||||
t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key))
|
||||
var i = 0
|
||||
# `pairs` needs to yield in sorted order:
|
||||
for key, val in pairs(t):
|
||||
doAssert key == sorteddata[i][0]
|
||||
doAssert val == sorteddata[i][1]
|
||||
inc(i)
|
||||
|
||||
# check that lookup still works:
|
||||
for key, val in pairs(t):
|
||||
doAssert val == t[key]
|
||||
# check that insert still works:
|
||||
t["newKeyHere"] = 80
|
||||
|
||||
|
||||
orderedTableSortTest()
|
||||
echo "true"
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ block orderedTableTest1:
|
||||
block countTableTest1:
|
||||
var s = data.toTable
|
||||
var t = newCountTable[string]()
|
||||
for k in s.Keys: t.inc(k)
|
||||
for k in s.keys: t.inc(k)
|
||||
for k in t.keys: assert t[k] == 1
|
||||
t.inc("90", 3)
|
||||
t.inc("12", 2)
|
||||
@@ -1,453 +0,0 @@
|
||||
import irc, sockets, asyncio, json, os, strutils, times, redis
|
||||
|
||||
type
|
||||
TDb* = object
|
||||
r*: Redis
|
||||
lastPing: float
|
||||
|
||||
TBuildResult* = enum
|
||||
bUnknown, bFail, bSuccess
|
||||
|
||||
TTestResult* = enum
|
||||
tUnknown, tFail, tSuccess
|
||||
|
||||
TEntry* = tuple[c: TCommit, p: seq[TPlatform]]
|
||||
|
||||
TCommit* = object
|
||||
commitMsg*, username*, hash*: string
|
||||
date*: Time
|
||||
|
||||
TPlatform* = object
|
||||
buildResult*: TBuildResult
|
||||
testResult*: TTestResult
|
||||
failReason*, platform*: string
|
||||
total*, passed*, skipped*, failed*: BiggestInt
|
||||
csources*: bool
|
||||
|
||||
const
|
||||
listName = "commits"
|
||||
failOnExisting = false
|
||||
|
||||
proc open*(host = "localhost", port: Port): TDb =
|
||||
result.r = redis.open(host, port)
|
||||
result.lastPing = epochTime()
|
||||
|
||||
discard """proc customHSet(database: TDb, name, field, value: string) =
|
||||
if database.r.hSet(name, field, value).int == 0:
|
||||
if failOnExisting:
|
||||
assert(false)
|
||||
else:
|
||||
echo("[Warning:REDIS] ", field, " already exists in ", name)"""
|
||||
|
||||
proc updateProperty*(database: TDb, commitHash, platform, property,
|
||||
value: string) =
|
||||
var name = platform & ":" & commitHash
|
||||
if database.r.hSet(name, property, value).int == 0:
|
||||
echo("[INFO:REDIS] '$1' field updated in hash" % [property])
|
||||
else:
|
||||
echo("[INFO:REDIS] '$1' new field added to hash" % [property])
|
||||
|
||||
proc globalProperty*(database: TDb, commitHash, property, value: string) =
|
||||
if database.r.hSet(commitHash, property, value).int == 0:
|
||||
echo("[INFO:REDIS] '$1' field updated in hash" % [property])
|
||||
else:
|
||||
echo("[INFO:REDIS] '$1' new field added to hash" % [property])
|
||||
|
||||
proc addCommit*(database: TDb, commitHash, commitMsg, user: string) =
|
||||
# Add the commit hash to the `commits` list.
|
||||
discard database.r.lPush(listName, commitHash)
|
||||
# Add the commit message, current date and username as a property
|
||||
globalProperty(database, commitHash, "commitMsg", commitMsg)
|
||||
globalProperty(database, commitHash, "date", $int(getTime()))
|
||||
globalProperty(database, commitHash, "username", user)
|
||||
|
||||
proc keepAlive*(database: var TDb) =
|
||||
## Keep the connection alive. Ping redis in this case. This functions does
|
||||
## not guarantee that redis will be pinged.
|
||||
var t = epochTime()
|
||||
if t - database.lastPing >= 60.0:
|
||||
echo("PING -> redis")
|
||||
assert(database.r.ping() == "PONG")
|
||||
database.lastPing = t
|
||||
|
||||
proc getCommits*(database: TDb,
|
||||
plStr: var seq[string]): seq[TEntry] =
|
||||
result = @[]
|
||||
var commitsRaw = database.r.lrange("commits", 0, -1)
|
||||
for c in items(commitsRaw):
|
||||
var commit: TCommit
|
||||
commit.hash = c
|
||||
for key, value in database.r.hPairs(c):
|
||||
case normalize(key)
|
||||
of "commitmsg": commit.commitMsg = value
|
||||
of "date": commit.date = Time(parseInt(value))
|
||||
of "username": commit.username = value
|
||||
else:
|
||||
echo(key)
|
||||
assert(false)
|
||||
|
||||
var platformsRaw = database.r.lrange(c & ":platforms", 0, -1)
|
||||
var platforms: seq[TPlatform] = @[]
|
||||
for p in items(platformsRaw):
|
||||
var platform: TPlatform
|
||||
for key, value in database.r.hPairs(p & ":" & c):
|
||||
case normalize(key)
|
||||
of "buildresult":
|
||||
platform.buildResult = parseInt(value).TBuildResult
|
||||
of "testresult":
|
||||
platform.testResult = parseInt(value).TTestResult
|
||||
of "failreason":
|
||||
platform.failReason = value
|
||||
of "total":
|
||||
platform.total = parseBiggestInt(value)
|
||||
of "passed":
|
||||
platform.passed = parseBiggestInt(value)
|
||||
of "skipped":
|
||||
platform.skipped = parseBiggestInt(value)
|
||||
of "failed":
|
||||
platform.failed = parseBiggestInt(value)
|
||||
of "csources":
|
||||
platform.csources = if value == "t": true else: false
|
||||
else:
|
||||
echo(normalize(key))
|
||||
assert(false)
|
||||
|
||||
platform.platform = p
|
||||
|
||||
platforms.add(platform)
|
||||
if p notin plStr:
|
||||
plStr.add(p)
|
||||
result.add((commit, platforms))
|
||||
|
||||
proc commitExists*(database: TDb, commit: string, starts = false): bool =
|
||||
# TODO: Consider making the 'commits' list a set.
|
||||
for c in items(database.r.lrange("commits", 0, -1)):
|
||||
if starts:
|
||||
if c.startsWith(commit): return true
|
||||
else:
|
||||
if c == commit: return true
|
||||
return false
|
||||
|
||||
proc platformExists*(database: TDb, commit: string, platform: string): bool =
|
||||
for p in items(database.r.lrange(commit & ":" & "platforms", 0, -1)):
|
||||
if p == platform: return true
|
||||
|
||||
proc expandHash*(database: TDb, commit: string): string =
|
||||
for c in items(database.r.lrange("commits", 0, -1)):
|
||||
if c.startsWith(commit): return c
|
||||
assert false
|
||||
|
||||
proc isNewest*(database: TDb, commit: string): bool =
|
||||
return database.r.lIndex("commits", 0) == commit
|
||||
|
||||
proc getNewest*(database: TDb): string =
|
||||
return database.r.lIndex("commits", 0)
|
||||
|
||||
proc addPlatform*(database: TDb, commit: string, platform: string) =
|
||||
assert database.commitExists(commit)
|
||||
assert (not database.platformExists(commit, platform))
|
||||
var name = platform & ":" & commit
|
||||
if database.r.exists(name):
|
||||
if failOnExisting: quit("[FAIL] " & name & " already exists!", 1)
|
||||
else: echo("[Warning] " & name & " already exists!")
|
||||
|
||||
discard database.r.lPush(commit & ":" & "platforms", platform)
|
||||
|
||||
proc `[]`*(p: seq[TPlatform], name: string): TPlatform =
|
||||
for platform in items(p):
|
||||
if platform.platform == name:
|
||||
return platform
|
||||
raise newException(ValueError, name & " platforms not found in commits.")
|
||||
|
||||
proc contains*(p: seq[TPlatform], s: string): bool =
|
||||
for i in items(p):
|
||||
if i.platform == s:
|
||||
return true
|
||||
|
||||
|
||||
type
|
||||
PState = ref TState
|
||||
TState = object of RootObj
|
||||
dispatcher: Dispatcher
|
||||
sock: AsyncSocket
|
||||
ircClient: PAsyncIRC
|
||||
hubPort: Port
|
||||
database: TDb
|
||||
dbConnected: bool
|
||||
|
||||
TSeenType = enum
|
||||
PSeenJoin, PSeenPart, PSeenMsg, PSeenNick, PSeenQuit
|
||||
|
||||
TSeen = object
|
||||
nick: string
|
||||
channel: string
|
||||
timestamp: Time
|
||||
case kind*: TSeenType
|
||||
of PSeenJoin: nil
|
||||
of PSeenPart, PSeenQuit, PSeenMsg:
|
||||
msg: string
|
||||
of PSeenNick:
|
||||
newNick: string
|
||||
|
||||
const
|
||||
ircServer = "irc.freenode.net"
|
||||
joinChans = @["#nim"]
|
||||
botNickname = "NimBot"
|
||||
|
||||
proc setSeen(d: TDb, s: TSeen) =
|
||||
discard d.r.del("seen:" & s.nick)
|
||||
|
||||
var hashToSet = @[("type", $s.kind.int), ("channel", s.channel),
|
||||
("timestamp", $s.timestamp.int)]
|
||||
case s.kind
|
||||
of PSeenJoin: discard
|
||||
of PSeenPart, PSeenMsg, PSeenQuit:
|
||||
hashToSet.add(("msg", s.msg))
|
||||
of PSeenNick:
|
||||
hashToSet.add(("newnick", s.newNick))
|
||||
|
||||
d.r.hMSet("seen:" & s.nick, hashToSet)
|
||||
|
||||
proc getSeen(d: TDb, nick: string, s: var TSeen): bool =
|
||||
if d.r.exists("seen:" & nick):
|
||||
result = true
|
||||
s.nick = nick
|
||||
# Get the type first
|
||||
s.kind = d.r.hGet("seen:" & nick, "type").parseInt.TSeenType
|
||||
|
||||
for key, value in d.r.hPairs("seen:" & nick):
|
||||
case normalize(key)
|
||||
of "type":
|
||||
discard
|
||||
#s.kind = value.parseInt.TSeenType
|
||||
of "channel":
|
||||
s.channel = value
|
||||
of "timestamp":
|
||||
s.timestamp = Time(value.parseInt)
|
||||
of "msg":
|
||||
s.msg = value
|
||||
of "newnick":
|
||||
s.newNick = value
|
||||
|
||||
template createSeen(typ: TSeenType, n, c: string): stmt {.immediate, dirty.} =
|
||||
var seenNick: TSeen
|
||||
seenNick.kind = typ
|
||||
seenNick.nick = n
|
||||
seenNick.channel = c
|
||||
seenNick.timestamp = getTime()
|
||||
|
||||
proc parseReply(line: string, expect: string): bool =
|
||||
var jsonDoc = parseJson(line)
|
||||
return jsonDoc["reply"].str == expect
|
||||
|
||||
proc limitCommitMsg(m: string): string =
|
||||
## Limits the message to 300 chars and adds ellipsis.
|
||||
var m1 = m
|
||||
if NewLines in m1:
|
||||
m1 = m1.splitLines()[0]
|
||||
|
||||
if m1.len >= 300:
|
||||
m1 = m1[0..300]
|
||||
|
||||
if m1.len >= 300 or NewLines in m: m1.add("... ")
|
||||
|
||||
if NewLines in m: m1.add($m.splitLines().len & " more lines")
|
||||
|
||||
return m1
|
||||
|
||||
proc handleWebMessage(state: PState, line: string) =
|
||||
echo("Got message from hub: " & line)
|
||||
var json = parseJson(line)
|
||||
if json.hasKey("payload"):
|
||||
for i in 0..min(4, json["payload"]["commits"].len-1):
|
||||
var commit = json["payload"]["commits"][i]
|
||||
# Create the message
|
||||
var message = ""
|
||||
message.add(json["payload"]["repository"]["owner"]["name"].str & "/" &
|
||||
json["payload"]["repository"]["name"].str & " ")
|
||||
message.add(commit["id"].str[0..6] & " ")
|
||||
message.add(commit["author"]["name"].str & " ")
|
||||
message.add("[+" & $commit["added"].len & " ")
|
||||
message.add("±" & $commit["modified"].len & " ")
|
||||
message.add("-" & $commit["removed"].len & "]: ")
|
||||
message.add(limitCommitMsg(commit["message"].str))
|
||||
|
||||
# Send message to #nim.
|
||||
discard state.ircClient.privmsg(joinChans[0], message)
|
||||
elif json.hasKey("redisinfo"):
|
||||
assert json["redisinfo"].hasKey("port")
|
||||
#let redisPort = json["redisinfo"]["port"].num
|
||||
state.dbConnected = true
|
||||
|
||||
proc hubConnect(state: PState)
|
||||
proc handleConnect(s: AsyncSocket, state: PState) =
|
||||
try:
|
||||
# Send greeting
|
||||
var obj = newJObject()
|
||||
obj["name"] = newJString("irc")
|
||||
obj["platform"] = newJString("?")
|
||||
state.sock.send($obj & "\c\L")
|
||||
|
||||
# Wait for reply.
|
||||
var line = ""
|
||||
sleep(1500)
|
||||
if state.sock.recvLine(line):
|
||||
assert(line != "")
|
||||
doAssert parseReply(line, "OK")
|
||||
echo("The hub accepted me!")
|
||||
else:
|
||||
raise newException(ValueError,
|
||||
"Hub didn't accept me. Waited 1.5 seconds.")
|
||||
|
||||
# ask for the redis info
|
||||
var riobj = newJObject()
|
||||
riobj["do"] = newJString("redisinfo")
|
||||
state.sock.send($riobj & "\c\L")
|
||||
|
||||
except OsError:
|
||||
echo(getCurrentExceptionMsg())
|
||||
s.close()
|
||||
echo("Waiting 5 seconds...")
|
||||
sleep(5000)
|
||||
state.hubConnect()
|
||||
|
||||
proc handleRead(s: AsyncSocket, state: PState) =
|
||||
var line = ""
|
||||
if state.sock.recvLine(line):
|
||||
if line != "":
|
||||
# Handle the message
|
||||
state.handleWebMessage(line)
|
||||
else:
|
||||
echo("Disconnected from hub: ", osErrorMsg())
|
||||
s.close()
|
||||
echo("Reconnecting...")
|
||||
state.hubConnect()
|
||||
else:
|
||||
echo(osErrorMsg())
|
||||
|
||||
proc hubConnect(state: PState) =
|
||||
state.sock = asyncSocket()
|
||||
state.sock.connect("127.0.0.1", state.hubPort)
|
||||
state.sock.handleConnect =
|
||||
proc (s: AsyncSocket) =
|
||||
handleConnect(s, state)
|
||||
state.sock.handleRead =
|
||||
proc (s: AsyncSocket) =
|
||||
handleRead(s, state)
|
||||
|
||||
state.dispatcher.register(state.sock)
|
||||
|
||||
proc handleIrc(irc: PAsyncIRC, event: TIRCEvent, state: PState) =
|
||||
case event.typ
|
||||
of EvConnected: discard
|
||||
of EvDisconnected:
|
||||
while not state.ircClient.isConnected:
|
||||
try:
|
||||
state.ircClient.connect()
|
||||
except:
|
||||
echo("Error reconnecting: ", getCurrentExceptionMsg())
|
||||
|
||||
echo("Waiting 5 seconds...")
|
||||
sleep(5000)
|
||||
echo("Reconnected successfully!")
|
||||
of EvMsg:
|
||||
echo("< ", event.raw)
|
||||
case event.cmd
|
||||
of MPrivMsg:
|
||||
let msg = event.params[event.params.len-1]
|
||||
let words = msg.split(' ')
|
||||
template pm(msg: string): stmt =
|
||||
state.ircClient.privmsg(event.origin, msg)
|
||||
case words[0]
|
||||
of "!ping": pm("pong")
|
||||
of "!lag":
|
||||
if state.ircClient.getLag != -1.0:
|
||||
var lag = state.ircClient.getLag
|
||||
lag = lag * 1000.0
|
||||
pm($int(lag) & "ms between me and the server.")
|
||||
else:
|
||||
pm("Unknown.")
|
||||
of "!seen":
|
||||
if words.len > 1:
|
||||
let nick = words[1]
|
||||
if nick == botNickname:
|
||||
pm("Yes, I see myself.")
|
||||
echo(nick)
|
||||
var seenInfo: TSeen
|
||||
if state.database.getSeen(nick, seenInfo):
|
||||
#var mSend = ""
|
||||
case seenInfo.kind
|
||||
of PSeenMsg:
|
||||
pm("$1 was last seen on $2 in $3 saying: $4" %
|
||||
[seenInfo.nick, $seenInfo.timestamp,
|
||||
seenInfo.channel, seenInfo.msg])
|
||||
of PSeenJoin:
|
||||
pm("$1 was last seen on $2 joining $3" %
|
||||
[seenInfo.nick, $seenInfo.timestamp, seenInfo.channel])
|
||||
of PSeenPart:
|
||||
pm("$1 was last seen on $2 leaving $3 with message: $4" %
|
||||
[seenInfo.nick, $seenInfo.timestamp, seenInfo.channel,
|
||||
seenInfo.msg])
|
||||
of PSeenQuit:
|
||||
pm("$1 was last seen on $2 quitting with message: $3" %
|
||||
[seenInfo.nick, $seenInfo.timestamp, seenInfo.msg])
|
||||
of PSeenNick:
|
||||
pm("$1 was last seen on $2 changing nick to $3" %
|
||||
[seenInfo.nick, $seenInfo.timestamp, seenInfo.newNick])
|
||||
|
||||
else:
|
||||
pm("I have not seen " & nick)
|
||||
else:
|
||||
pm("Syntax: !seen <nick>")
|
||||
|
||||
# TODO: ... commands
|
||||
|
||||
# -- Seen
|
||||
# Log this as activity.
|
||||
createSeen(PSeenMsg, event.nick, event.origin)
|
||||
seenNick.msg = msg
|
||||
state.database.setSeen(seenNick)
|
||||
of MJoin:
|
||||
createSeen(PSeenJoin, event.nick, event.origin)
|
||||
state.database.setSeen(seenNick)
|
||||
of MPart:
|
||||
createSeen(PSeenPart, event.nick, event.origin)
|
||||
let msg = event.params[event.params.high]
|
||||
seenNick.msg = msg
|
||||
state.database.setSeen(seenNick)
|
||||
of MQuit:
|
||||
createSeen(PSeenQuit, event.nick, event.origin)
|
||||
let msg = event.params[event.params.high]
|
||||
seenNick.msg = msg
|
||||
state.database.setSeen(seenNick)
|
||||
of MNick:
|
||||
createSeen(PSeenNick, event.nick, "#nim")
|
||||
seenNick.newNick = event.params[0]
|
||||
state.database.setSeen(seenNick)
|
||||
else:
|
||||
discard # TODO: ?
|
||||
|
||||
proc open(port: Port = Port(5123)): PState =
|
||||
var res: PState
|
||||
new(res)
|
||||
res.dispatcher = newDispatcher()
|
||||
|
||||
res.hubPort = port
|
||||
res.hubConnect()
|
||||
let hirc =
|
||||
proc (a: PAsyncIRC, ev: TIRCEvent) =
|
||||
handleIrc(a, ev, res)
|
||||
# Connect to the irc server.
|
||||
res.ircClient = AsyncIrc(ircServer, nick = botNickname, user = botNickname,
|
||||
joinChans = joinChans, ircEvent = hirc)
|
||||
res.ircClient.connect()
|
||||
res.dispatcher.register(res.ircClient)
|
||||
|
||||
res.dbConnected = false
|
||||
result = res
|
||||
|
||||
var state = tircbot.open() # Connect to the website and the IRC server.
|
||||
|
||||
while state.dispatcher.poll():
|
||||
if state.dbConnected:
|
||||
state.database.keepAlive()
|
||||
@@ -11,7 +11,7 @@ fpqeew
|
||||
[11, 12, 13]
|
||||
[11, 12, 13]
|
||||
[11, 12, 13]
|
||||
{ "key1": 11, "key2": 12, "key3": 13}
|
||||
{"key1": 11, "key2": 12, "key3": 13}
|
||||
[11, 12, 13]
|
||||
<Students>
|
||||
<Student Name="Aprilfoo" />
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
discard """
|
||||
output: '''true'''
|
||||
"""
|
||||
|
||||
import hashes, tables
|
||||
|
||||
const
|
||||
data = {
|
||||
"34": 123456, "12": 789,
|
||||
"90": 343, "0": 34404,
|
||||
"1": 344004, "2": 344774,
|
||||
"3": 342244, "4": 3412344,
|
||||
"5": 341232144, "6": 34214544,
|
||||
"7": 3434544, "8": 344544,
|
||||
"9": 34435644, "---00": 346677844,
|
||||
"10": 34484, "11": 34474, "19": 34464,
|
||||
"20": 34454, "30": 34141244, "40": 344114,
|
||||
"50": 344490, "60": 344491, "70": 344492,
|
||||
"80": 344497}
|
||||
|
||||
sorteddata = {
|
||||
"---00": 346677844,
|
||||
"0": 34404,
|
||||
"1": 344004,
|
||||
"10": 34484,
|
||||
"11": 34474,
|
||||
"12": 789,
|
||||
"19": 34464,
|
||||
"2": 344774, "20": 34454,
|
||||
"3": 342244, "30": 34141244,
|
||||
"34": 123456,
|
||||
"4": 3412344, "40": 344114,
|
||||
"5": 341232144, "50": 344490,
|
||||
"6": 34214544, "60": 344491,
|
||||
"7": 3434544, "70": 344492,
|
||||
"8": 344544, "80": 344497,
|
||||
"9": 34435644,
|
||||
"90": 343}
|
||||
|
||||
block tableTest1:
|
||||
var t = initTable[tuple[x, y: int], string]()
|
||||
t[(0,0)] = "00"
|
||||
t[(1,0)] = "10"
|
||||
t[(0,1)] = "01"
|
||||
t[(1,1)] = "11"
|
||||
for x in 0..1:
|
||||
for y in 0..1:
|
||||
assert t[(x,y)] == $x & $y
|
||||
assert($t ==
|
||||
"{(x: 0, y: 0): 00, (x: 0, y: 1): 01, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
|
||||
|
||||
block tableTest2:
|
||||
var t = initTable[string, float]()
|
||||
t["test"] = 1.2345
|
||||
t["111"] = 1.000043
|
||||
t["123"] = 1.23
|
||||
t.del("111")
|
||||
|
||||
t["012"] = 67.9
|
||||
t["123"] = 1.5 # test overwriting
|
||||
|
||||
assert t["123"] == 1.5
|
||||
assert t["111"] == 0.0 # deleted
|
||||
assert(not hasKey(t, "111"))
|
||||
|
||||
for key, val in items(data): t[key] = val.toFloat
|
||||
for key, val in items(data): assert t[key] == val.toFloat
|
||||
|
||||
|
||||
block orderedTableTest1:
|
||||
var t = initOrderedTable[string, int](2)
|
||||
for key, val in items(data): t[key] = val
|
||||
for key, val in items(data): assert t[key] == val
|
||||
var i = 0
|
||||
# `pairs` needs to yield in insertion order:
|
||||
for key, val in pairs(t):
|
||||
assert key == data[i][0]
|
||||
assert val == data[i][1]
|
||||
inc(i)
|
||||
|
||||
for key, val in mpairs(t): val = 99
|
||||
for val in mvalues(t): assert val == 99
|
||||
|
||||
block countTableTest1:
|
||||
var s = data.toTable
|
||||
var t = initCountTable[string]()
|
||||
for k in s.keys: t.inc(k)
|
||||
for k in t.keys: assert t[k] == 1
|
||||
t.inc("90", 3)
|
||||
t.inc("12", 2)
|
||||
t.inc("34", 1)
|
||||
assert t.largest()[0] == "90"
|
||||
|
||||
t.sort()
|
||||
var i = 0
|
||||
for k, v in t.pairs:
|
||||
case i
|
||||
of 0: assert k == "90" and v == 4
|
||||
of 1: assert k == "12" and v == 3
|
||||
of 2: assert k == "34" and v == 2
|
||||
else: break
|
||||
inc i
|
||||
|
||||
block SyntaxTest:
|
||||
var x = toTable[int, string]({:})
|
||||
|
||||
proc orderedTableSortTest() =
|
||||
var t = initOrderedTable[string, int](2)
|
||||
for key, val in items(data): t[key] = val
|
||||
for key, val in items(data): assert t[key] == val
|
||||
t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key))
|
||||
var i = 0
|
||||
# `pairs` needs to yield in sorted order:
|
||||
for key, val in pairs(t):
|
||||
doAssert key == sorteddata[i][0]
|
||||
doAssert val == sorteddata[i][1]
|
||||
inc(i)
|
||||
|
||||
# check that lookup still works:
|
||||
for key, val in pairs(t):
|
||||
doAssert val == t[key]
|
||||
# check that insert still works:
|
||||
t["newKeyHere"] = 80
|
||||
|
||||
|
||||
orderedTableSortTest()
|
||||
echo "true"
|
||||
|
||||
Reference in New Issue
Block a user