From 10335fd7264560e9b5a6ca4b2b5fe8e28e78209b Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 11 Feb 2015 17:42:28 +0100 Subject: [PATCH] fixed minor bugs; cleaned up tests --- compiler/sempass2.nim | 3 +- lib/core/macros.nim | 20 +- lib/pure/collections/tables.nim | 2 +- lib/pure/math.nim | 8 +- lib/pure/net.nim | 9 +- lib/pure/os.nim | 6 +- lib/pure/times.nim | 102 ++-- lib/system.nim | 38 +- lib/system/repr.nim | 6 +- tests/collections/tindexby.nim | 22 + tests/{table => collections}/ttableconstr.nim | 0 tests/collections/ttables.nim | 142 +++++- tests/{table => collections}/ttables2.nim | 0 .../ttablesref.nim} | 2 +- .../ttablesref2.nim} | 0 tests/stdlib/tircbot.nim | 453 ------------------ tests/stdlib/tmitems.nim | 2 +- tests/table/ttables.nim | 128 ----- todo.txt | 1 - 19 files changed, 243 insertions(+), 701 deletions(-) create mode 100644 tests/collections/tindexby.nim rename tests/{table => collections}/ttableconstr.nim (100%) rename tests/{table => collections}/ttables2.nim (100%) rename tests/{table/ptables.nim => collections/ttablesref.nim} (99%) rename tests/{table/ptables2.nim => collections/ttablesref2.nim} (100%) delete mode 100644 tests/stdlib/tircbot.nim delete mode 100644 tests/table/ttables.nim diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index ede556a70..6fa7c756e 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -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]) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 22b9c4907..4c561df70 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -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.} = diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 9dcc97148..671f767cf 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -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. diff --git a/lib/pure/math.nim b/lib/pure/math.nim index b9e057e78..1690377ff 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -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..= 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 ") - - # 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() diff --git a/tests/stdlib/tmitems.nim b/tests/stdlib/tmitems.nim index bf67d2b7b..2c0a0392a 100644 --- a/tests/stdlib/tmitems.nim +++ b/tests/stdlib/tmitems.nim @@ -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] diff --git a/tests/table/ttables.nim b/tests/table/ttables.nim deleted file mode 100644 index de4aaed5e..000000000 --- a/tests/table/ttables.nim +++ /dev/null @@ -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" - diff --git a/todo.txt b/todo.txt index 706954f65..57cfea017 100644 --- a/todo.txt +++ b/todo.txt @@ -41,7 +41,6 @@ Misc - make tuple unpacking work in a non-var/let context - built-in 'getImpl' - prevent 'alloc(TypeWithGCedMemory)' -- some table related tests are wrong (memory usage checks) Bugs