diff options
29 files changed, 240 insertions, 66 deletions
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 46a9177ad..ff8f768bd 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -181,7 +181,7 @@ proc mangle*(name: string): string = of '_': # we generate names like 'foo_9' for scope disambiguations and so # disallow this here: - if i < name.len-1 and name[i+1] in Digits: + if i > 0 and i < name.len-1 and name[i+1] in Digits: discard else: add(result, c) diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index ebd2f557f..779d6d2a4 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -218,8 +218,13 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; of tyTuple: if inst: result = newNodeX(nkTupleTy) - for s in t.n.sons: - result.add newIdentDefs(s) + # only named tuples have a node, unnamed tuples don't + if t.n.isNil: + for subType in t.sons: + result.add mapTypeToAst(subType, info) + else: + for s in t.n.sons: + result.add newIdentDefs(s) else: result = mapTypeToBracket("tuple", mTuple, t, info) of tySet: result = mapTypeToBracket("set", mSet, t, info) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index dda4b033f..4013182af 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -516,23 +516,23 @@ iterator findIter*(str: string, pattern: Regex, start = 0, endpos = int.high): R let unicode = uint32(getinfo[culong](pattern, pcre.INFO_OPTIONS) and pcre.UTF8) > 0u32 let strlen = if endpos == int.high: str.len else: endpos+1 - var offset = start var match: Option[RegexMatch] + var neverMatched = true + while true: var flags = 0 - if match.isSome and match.get.matchBounds.a > match.get.matchBounds.b: # 0-len match flags = pcre.NOTEMPTY_ATSTART - match = str.matchImpl(pattern, offset, endpos, flags) if match.isNone: # either the end of the input or the string - # cannot be split here - if offset >= strlen: + # cannot be split here - we also need to bail + # if we've never matched and we've already tried to... + if offset >= strlen or neverMatched: break if matchesCrLf and offset < (str.len - 1) and @@ -546,11 +546,11 @@ iterator findIter*(str: string, pattern: Regex, start = 0, endpos = int.high): R else: offset += 1 else: + neverMatched = false offset = match.get.matchBounds.b + 1 yield match.get - proc find*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[RegexMatch] = ## Finds the given pattern in the string between the end and start ## positions. diff --git a/lib/nimbase.h b/lib/nimbase.h index a5d2616e7..d6763f8ff 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -39,6 +39,7 @@ __clang__ # pragma GCC diagnostic ignored "-Wswitch-bool" # pragma GCC diagnostic ignored "-Wmacro-redefined" # pragma GCC diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers" +# pragma GCC diagnostic ignored "-Wpointer-bool-conversion" #endif #if defined(_MSC_VER) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 47247dd7c..ce63d780c 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -870,7 +870,7 @@ proc buildLinesHTMLTable(d: PDoc; params: CodeBlockParams, code: string): d.config.getOrDefault"doc.listing_end" % id) return - var codeLines = 1 + code.strip.countLines + var codeLines = code.strip.countLines assert codeLines > 0 result.beginTable = """<table class="line-nums-table"><tbody><tr><td class="blob-line-nums"><pre class="line-nums">""" var line = params.startLine diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 7fa686f00..1696c4ed9 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -167,8 +167,12 @@ type callbacks: Deque[proc ()] proc processTimers(p: PDispatcherBase) {.inline.} = - while p.timers.len > 0 and epochTime() >= p.timers[0].finishAt: + #Process just part if timers at a step + var count = p.timers.len + let t = epochTime() + while count > 0 and t >= p.timers[0].finishAt: p.timers.pop().fut.complete() + dec count proc processPendingCallbacks(p: PDispatcherBase) = while p.callbacks.len > 0: diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 672eb34a0..80aa8bb2c 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -31,7 +31,7 @@ ## ## waitFor server.serve(Port(8080), cb) -import tables, asyncnet, asyncdispatch, parseutils, uri, strutils, nativesockets +import tables, asyncnet, asyncdispatch, parseutils, uri, strutils import httpcore export httpcore except parseHeader @@ -209,7 +209,9 @@ proc processClient(client: AsyncSocket, address: string, continue else: request.body = await client.recv(contentLength) - assert request.body.len == contentLength + if request.body.len != contentLength: + await request.respond(Http400, "Bad Request. Content-Length does not match actual.") + continue elif request.reqMethod == HttpPost: await request.respond(Http400, "Bad Request. No Content-Length.") continue @@ -241,7 +243,7 @@ proc serve*(server: AsyncHttpServer, port: Port, ## specified address and port. ## ## When a request is made by a client the specified callback will be called. - server.socket = newAsyncSocket(AF_INET6) + server.socket = newAsyncSocket() if server.reuseAddr: server.socket.setSockOpt(OptReuseAddr, true) if server.reusePort: diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index 2fc0b1c5e..eee03d7ae 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -49,7 +49,7 @@ template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediat ## `newline` is added. var total = ((len(s) + 2) div 3) * 4 var numLines = (total + lineLen - 1) div lineLen - if numLines > 0: inc(total, (numLines-1) * newLine.len) + if numLines > 0: inc(total, (numLines - 1) * newLine.len) result = newString(total) var i = 0 @@ -66,7 +66,8 @@ template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediat inc(r, 4) inc(i, 3) inc(currLine, 4) - if currLine >= lineLen and i != s.len-2: + # avoid index out of bounds when lineLen == encoded length + if currLine >= lineLen and i != s.len-2 and r < total: for x in items(newLine): result[r] = x inc(r) @@ -155,12 +156,17 @@ when isMainModule: assert encode("asure.") == "YXN1cmUu" assert encode("sure.") == "c3VyZS4=" + const testInputExpandsTo76 = "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++" + const testInputExpands = "++++++++++++++++++++++++++++++" const longText = """Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.""" const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.", - "asure.", longText] + "asure.", longText, testInputExpandsTo76, testInputExpands] + for t in items(tests): assert decode(encode(t)) == t + assert decode(encode(t, lineLen=40)) == t + assert decode(encode(t, lineLen=76)) == t \ No newline at end of file diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 28509caa1..de573bcb2 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -130,6 +130,52 @@ proc hasKeyOrPut*[A, B](t: var SharedTable[A, B], key: A, val: B): bool = withLock t: hasKeyOrPutImpl(enlarge) +proc withKey*[A, B](t: var SharedTable[A, B], key: A, + mapper: proc(key: A, val: var B, pairExists: var bool)) = + ## Computes a new mapping for the ``key`` with the specified ``mapper`` + ## procedure. + ## + ## The ``mapper`` takes 3 arguments: + ## #. ``key`` - the current key, if it exists, or the key passed to + ## ``withKey`` otherwise; + ## #. ``val`` - the current value, if the key exists, or default value + ## of the type otherwise; + ## #. ``pairExists`` - ``true`` if the key exists, ``false`` otherwise. + ## The ``mapper`` can can modify ``val`` and ``pairExists`` values to change + ## the mapping of the key or delete it from the table. + ## When adding a value, make sure to set ``pairExists`` to ``true`` along + ## with modifying the ``val``. + ## + ## The operation is performed atomically and other operations on the table + ## will be blocked while the ``mapper`` is invoked, so it should be short and + ## simple. + ## + ## Example usage: + ## + ## .. code-block:: nim + ## + ## # If value exists, decrement it. + ## # If it becomes zero or less, delete the key + ## t.withKey(1'i64) do (k: int64, v: var int, pairExists: var bool): + ## if pairExists: + ## dec v + ## if v <= 0: + ## pairExists = false + withLock t: + var hc: Hash + var index = rawGet(t, key, hc) + + var pairExists = index >= 0 + if pairExists: + mapper(t.data[index].key, t.data[index].val, pairExists) + if not pairExists: + delImplIdx(t, index) + else: + var val: B + mapper(key, val, pairExists) + if pairExists: + maybeRehashPutImpl(enlarge) + proc `[]=`*[A, B](t: var SharedTable[A, B], key: A, val: B) = ## puts a (key, value)-pair into `t`. withLock t: diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index 5e871f08b..c0d45c392 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -120,9 +120,7 @@ template default[T](t: typedesc[T]): T = var v: T v -template delImpl() {.dirty.} = - var hc: Hash - var i = rawGet(t, key, hc) +template delImplIdx(t, i) = let msk = maxHash(t) if i >= 0: dec(t.counter) @@ -145,6 +143,11 @@ template delImpl() {.dirty.} = else: shallowCopy(t.data[j], t.data[i]) # data[j] will be marked EMPTY next loop +template delImpl() {.dirty.} = + var hc: Hash + var i = rawGet(t, key, hc) + delImplIdx(t, i) + template clearImpl() {.dirty.} = for i in 0 .. <t.data.len: when compiles(t.data[i].hcode): # CountTable records don't contain a hcode diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index e053f4427..b6ef30e7c 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -23,7 +23,6 @@ when not nimCoroutines and not defined(nimdoc): {.error: "Coroutines require -d:nimCoroutines".} import os -import macros import lists include system/timers @@ -120,27 +119,38 @@ const CORO_FINISHED = 2 type - Stack = object + Stack {.pure.} = object top: pointer # Top of the stack. Pointer used for deallocating stack if we own it. bottom: pointer # Very bottom of the stack, acts as unique stack identifier. size: int - Coroutine = ref object + Coroutine {.pure.} = object execContext: Context fn: proc() state: int lastRun: Ticks sleepTime: float stack: Stack + reference: CoroutineRef + + CoroutinePtr = ptr Coroutine + + CoroutineRef* = ref object + ## CoroutineRef holds a pointer to actual coroutine object. Public API always returns + ## CoroutineRef instead of CoroutinePtr in order to allow holding a reference to coroutine + ## object while it can be safely deallocated by coroutine scheduler loop. In this case + ## Coroutine.reference.coro is set to nil. Public API checks for for it being nil and + ## gracefully fails if it is nil. + coro: CoroutinePtr CoroutineLoopContext = ref object - coroutines: DoublyLinkedList[Coroutine] - current: DoublyLinkedNode[Coroutine] + coroutines: DoublyLinkedList[CoroutinePtr] + current: DoublyLinkedNode[CoroutinePtr] loop: Coroutine var ctx {.threadvar.}: CoroutineLoopContext -proc getCurrent(): Coroutine = +proc getCurrent(): CoroutinePtr = ## Returns current executing coroutine object. var node = ctx.current if node != nil: @@ -151,7 +161,7 @@ proc initialize() = ## Initializes coroutine state of current thread. if ctx == nil: ctx = CoroutineLoopContext() - ctx.coroutines = initDoublyLinkedList[Coroutine]() + ctx.coroutines = initDoublyLinkedList[CoroutinePtr]() ctx.loop = Coroutine() ctx.loop.state = CORO_EXECUTING when coroBackend == CORO_BACKEND_FIBERS: @@ -159,7 +169,7 @@ proc initialize() = proc runCurrentTask() -proc switchTo(current, to: Coroutine) = +proc switchTo(current, to: CoroutinePtr) = ## Switches execution from `current` into `to` context. to.lastRun = getTicks() # Update position of current stack so gc invoked from another stack knows how much to scan. @@ -192,7 +202,7 @@ proc suspend*(sleepTime: float=0) = ## Until then other coroutines are executed. var current = getCurrent() current.sleepTime = sleepTime - switchTo(current, ctx.loop) + switchTo(current, addr(ctx.loop)) proc runCurrentTask() = ## Starts execution of current coroutine and updates it's state through coroutine's life. @@ -218,31 +228,33 @@ proc runCurrentTask() = suspend(0) # Exit coroutine without returning from coroExecWithStack() doAssert false -proc start*(c: proc(), stacksize: int=defaultStackSize) = +proc start*(c: proc(), stacksize: int=defaultStackSize): CoroutineRef {.discardable.} = ## Schedule coroutine for execution. It does not run immediately. if ctx == nil: initialize() - var coro = Coroutine() - coro.fn = c + var coro: CoroutinePtr when coroBackend == CORO_BACKEND_FIBERS: + coro = cast[CoroutinePtr](alloc0(sizeof(Coroutine))) coro.execContext = CreateFiberEx(stacksize, stacksize, FIBER_FLAG_FLOAT_SWITCH, (proc(p: pointer): void {.stdcall.} = runCurrentTask()), nil) coro.stack.size = stacksize else: - var stack: pointer - while stack == nil: - stack = alloc0(stacksize) - coro.stack.top = stack + coro = cast[CoroutinePtr](alloc0(sizeof(Coroutine) + stacksize)) + coro.stack.top = cast[pointer](cast[ByteAddress](coro) + sizeof(Coroutine)) + coro.stack.bottom = cast[pointer](cast[ByteAddress](coro.stack.top) + stacksize) when coroBackend == CORO_BACKEND_UCONTEXT: discard getcontext(coro.execContext) - coro.execContext.uc_stack.ss_sp = cast[pointer](cast[ByteAddress](stack) + stacksize) - coro.execContext.uc_stack.ss_size = coro.stack.size - coro.execContext.uc_link = addr ctx.loop.execContext + coro.execContext.uc_stack.ss_sp = coro.stack.top + coro.execContext.uc_stack.ss_size = stacksize + coro.execContext.uc_link = addr(ctx.loop.execContext) makecontext(coro.execContext, runCurrentTask, 0) + coro.fn = c coro.stack.size = stacksize coro.state = CORO_CREATED + coro.reference = CoroutineRef(coro: coro) ctx.coroutines.append(coro) + return coro.reference proc run*() = initialize() @@ -256,7 +268,7 @@ proc run*() = var remaining = current.sleepTime - (float(getTicks() - current.lastRun) / 1_000_000_000) if remaining <= 0: # Save main loop context. Suspending coroutine will resume after this statement with - switchTo(ctx.loop, current) + switchTo(addr(ctx.loop), current) else: if minDelay > 0 and remaining > 0: minDelay = min(remaining, minDelay) @@ -269,14 +281,14 @@ proc run*() = # If first coroutine ends then `prev` is nil even if more coroutines # are to be scheduled. next = ctx.current.next + current.reference.coro = nil ctx.coroutines.remove(ctx.current) GC_removeStack(current.stack.bottom) when coroBackend == CORO_BACKEND_FIBERS: DeleteFiber(current.execContext) else: dealloc(current.stack.top) - current.stack.top = nil - current.stack.bottom = nil + dealloc(current) ctx.current = next elif ctx.current == nil or ctx.current.next == nil: ctx.current = ctx.coroutines.head @@ -284,13 +296,10 @@ proc run*() = else: ctx.current = ctx.current.next -proc alive*(c: proc()): bool = +proc alive*(c: CoroutineRef): bool = c.coro != nil and c.coro.state != CORO_FINISHED ## Returns ``true`` if coroutine has not returned, ``false`` otherwise. - for coro in items(ctx.coroutines): - if coro.fn == c: - return coro.state != CORO_FINISHED -proc wait*(c: proc(), interval=0.01) = +proc wait*(c: CoroutineRef, interval=0.01) = ## Returns only after coroutine ``c`` has returned. ``interval`` is time in seconds how often. while alive(c): suspend(interval) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 59918f766..662e75471 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -337,8 +337,16 @@ proc parseResponse(s: Socket, getBody: bool, timeout: int): Response = when not defined(ssl): type SSLContext = ref object var defaultSSLContext {.threadvar.}: SSLContext + when defined(ssl): defaultSSLContext = newContext(verifyMode = CVerifyNone) + template contextOrDefault(ctx: SSLContext): SSLContext = + var result = ctx + if ctx == nil: + if defaultSSLContext == nil: + defaultSSLContext = newContext(verifyMode = CVerifyNone) + result = defaultSSLContext + result proc newProxy*(url: string, auth = ""): Proxy = ## Constructs a new ``TProxy`` object. @@ -805,7 +813,7 @@ proc newHttpClient*(userAgent = defUserAgent, result.bodyStream = newStringStream() result.getBody = true when defined(ssl): - result.sslContext = sslContext + result.sslContext = contextOrDefault(sslContext) type AsyncHttpClient* = HttpClientBase[AsyncSocket] @@ -837,7 +845,7 @@ proc newAsyncHttpClient*(userAgent = defUserAgent, result.bodyStream = newFutureStream[string]("newAsyncHttpClient") result.getBody = true when defined(ssl): - result.sslContext = sslContext + result.sslContext = contextOrDefault(sslContext) proc close*(client: HttpClient | AsyncHttpClient) = ## Closes any connections held by the HTTP client. diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 65724f75a..598ee01d3 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -139,7 +139,7 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str result.add(arg) method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {. - raises: [Exception], + raises: [Exception], gcsafe, tags: [TimeEffect, WriteIOEffect, ReadIOEffect], base.} = ## Override this method in custom loggers. Default implementation does ## nothing. diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index d51dbd475..0a7ffb3b3 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -374,6 +374,22 @@ proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = result.addrList = cstringArrayToSeq(s.h_addr_list) result.length = int(s.h_length) +proc getHostname*(): string {.tags: [ReadIOEffect].} = + ## Returns the local hostname (not the FQDN) + # https://tools.ietf.org/html/rfc1035#section-2.3.1 + # https://tools.ietf.org/html/rfc2181#section-11 + const size = 64 + result = newString(size) + when useWinVersion: + let success = winlean.getHostname(result, size) + else: + # Posix + let success = posix.getHostname(result, size) + if success != 0.cint: + raiseOSError(osLastError()) + let x = len(cstring(result)) + result.setLen(x) + proc getSockDomain*(socket: SocketHandle): Domain = ## returns the socket's domain (AF_INET or AF_INET6). var name: SockAddr diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 9b2526337..a87df7f52 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -767,20 +767,16 @@ proc splitLines*(s: string): seq[string] {.noSideEffect, proc countLines*(s: string): int {.noSideEffect, rtl, extern: "nsuCountLines".} = - ## Returns the number of new line separators in the string `s`. + ## Returns the number of lines in the string `s`. ## ## This is the same as ``len(splitLines(s))``, but much more efficient ## because it doesn't modify the string creating temporal objects. Every ## `character literal <manual.html#character-literals>`_ newline combination ## (CR, LF, CR-LF) is supported. ## - ## Despite its name this proc might not actually return the *number of lines* - ## in `s` because the concept of what a line is can vary. For example, a - ## string like ``Hello world`` is a line of text, but the proc will return a - ## value of zero because there are no newline separators. Also, text editors - ## usually don't count trailing newline characters in a text file as a new - ## empty line, but this proc will. - var i = 0 + ## In this context, a line is any string seperated by a newline combination. + ## A line can be an empty string. + var i = 1 while i < s.len: case s[i] of '\c': diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 55f273154..dd7009d63 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -47,6 +47,8 @@ ## Tests can be nested, however failure of a nested test will not mark the ## parent test as failed. Setup and teardown are inherited. Setup can be ## overridden locally. +## Compiled test files return the number of failed test as exit code, while +## nim c -r <testfile.nim> exits with 0 or 1 import macros diff --git a/lib/system/channels.nim b/lib/system/channels.nim index 4b8b895a5..42096323c 100644 --- a/lib/system/channels.nim +++ b/lib/system/channels.nim @@ -13,6 +13,8 @@ ## ## **Note:** The current implementation of message passing is slow and does ## not work with cyclic data structures. +## **Note:** Channels cannot be passed between threads. Use globals or pass +## them by `ptr`. when not declared(NimString): {.error: "You must not import this module explicitly".} diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index e3b861fad..b0eb25616 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -290,9 +290,6 @@ elif stackIncreases: template forEachStackSlot(gch, gcMark: untyped) {.dirty.} = var registers {.noinit.}: C_JmpBuf - # sp will traverse the JMP_BUF as well (jmp_buf size is added, - # otherwise sp would be below the registers structure). - var regAddr = addr(registers) +% jmpbufSize if c_setjmp(registers) == 0'i32: # To fill the C stack with registers. for stack in gch.stack.items(): diff --git a/lib/upcoming/asyncdispatch.nim b/lib/upcoming/asyncdispatch.nim index 1787f062f..feee87bae 100644 --- a/lib/upcoming/asyncdispatch.nim +++ b/lib/upcoming/asyncdispatch.nim @@ -138,8 +138,12 @@ type callbacks: Deque[proc ()] proc processTimers(p: PDispatcherBase) {.inline.} = - while p.timers.len > 0 and epochTime() >= p.timers[0].finishAt: + #Process just part if timers at a step + var count = p.timers.len + let t = epochTime() + while count > 0 and t >= p.timers[0].finishAt: p.timers.pop().fut.complete() + dec count proc processPendingCallbacks(p: PDispatcherBase) = while p.callbacks.len > 0: diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index fa9ce9eed..1a251d0cc 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -542,6 +542,9 @@ proc gethostbyaddr*(ip: ptr InAddr, len: cuint, theType: cint): ptr Hostent {. proc gethostbyname*(name: cstring): ptr Hostent {. stdcall, importc: "gethostbyname", dynlib: ws2dll.} +proc gethostname*(hostname: cstring, len: cint): cint {. + stdcall, importc: "gethostname", dynlib: ws2dll.} + proc socket*(af, typ, protocol: cint): SocketHandle {. stdcall, importc: "socket", dynlib: ws2dll.} diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 0e06bc26f..a2988e841 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -1,8 +1,9 @@ discard """ + cmd: "nim c --threads:on $file" output: '''true''' """ -import hashes, tables +import hashes, tables, sharedtables const data = { @@ -211,6 +212,29 @@ block clearCountTableTest: t.clear() assert t.len() == 0 +block withKeyTest: + var t = initSharedTable[int, int]() + t.withKey(1) do (k: int, v: var int, pairExists: var bool): + assert(v == 0) + pairExists = true + v = 42 + assert(t.mget(1) == 42) + t.withKey(1) do (k: int, v: var int, pairExists: var bool): + assert(v == 42) + pairExists = false + try: + discard t.mget(1) + assert(false, "KeyError expected") + except KeyError: + discard + t.withKey(2) do (k: int, v: var int, pairExists: var bool): + pairExists = false + try: + discard t.mget(2) + assert(false, "KeyError expected") + except KeyError: + discard + proc orderedTableSortTest() = var t = initOrderedTable[string, int](2) for key, val in items(data): t[key] = val diff --git a/tests/coroutines/twait.nim b/tests/coroutines/twait.nim new file mode 100644 index 000000000..d8752b094 --- /dev/null +++ b/tests/coroutines/twait.nim @@ -0,0 +1,19 @@ +discard """ + output: "Exit 1\nExit 2" +""" +import coro + +var coro1: CoroutineRef + +proc testCoroutine1() = + for i in 0..<10: + suspend(0) + echo "Exit 1" + +proc testCoroutine2() = + coro1.wait() + echo "Exit 2" + +coro1 = coro.start(testCoroutine1) +coro.start(testCoroutine2) +run() diff --git a/tests/coroutines/twait.nim.cfg b/tests/coroutines/twait.nim.cfg new file mode 100644 index 000000000..b011bc585 --- /dev/null +++ b/tests/coroutines/twait.nim.cfg @@ -0,0 +1 @@ +-d:nimCoroutines diff --git a/tests/macros/tgettypeinst.nim b/tests/macros/tgettypeinst.nim index 22e03a119..255eff949 100644 --- a/tests/macros/tgettypeinst.nim +++ b/tests/macros/tgettypeinst.nim @@ -120,3 +120,7 @@ test(Tree): right: ref Tree test(proc (a: int, b: Foo[2,float])) test(proc (a: int, b: Foo[2,float]): Bar[3,int]) + +# bug #4862 +static: + discard typedesc[(int, int)].getTypeImpl diff --git a/tests/manyloc/keineschweine/lib/sg_gui.nim b/tests/manyloc/keineschweine/lib/sg_gui.nim index aae51baec..ffc4e8215 100644 --- a/tests/manyloc/keineschweine/lib/sg_gui.nim +++ b/tests/manyloc/keineschweine/lib/sg_gui.nim @@ -240,7 +240,7 @@ proc add*(m: PMessageArea, msg: ScChat) = of CPriv, CSystem: mmm.color = Green of CError: mmm.color = Red - mmm.lines = countLines(mmm.text)+1 + mmm.lines = countLines(mmm.text) m.messages.add mmm update m diff --git a/tests/stdlib/nre/find.nim b/tests/stdlib/nre/find.nim index 94fdd0bc1..caa953ff4 100644 --- a/tests/stdlib/nre/find.nim +++ b/tests/stdlib/nre/find.nim @@ -1,6 +1,7 @@ import unittest, sequtils import nre except toSeq import optional_nonstrict +import times, strutils suite "find": test "find text": @@ -25,3 +26,16 @@ suite "find": check("word word".findAll(re"\b") == @["", "", "", ""]) check("word\r\lword".findAll(re"(*ANYCRLF)(?m)$") == @["", ""]) check("слово слово".findAll(re"(*U)\b") == @["", "", "", ""]) + + test "bail early": + ## we expect nothing to be found and we should be bailing out early which means that + ## the timing difference between searching in small and large data should be well + ## within a tolerance margin + const small = 10 + const large = 1000 + var smallData = repeat("url.sequence = \"http://whatever.com/jwhrejrhrjrhrjhrrjhrjrhrjrh\" ", small) + var largeData = repeat("url.sequence = \"http://whatever.com/jwhrejrhrjrhrjhrrjhrjrhrjrh\" ", large) + var expression = re"^url.* = "(.*?)"" + + check(smallData.findAll(expression) == newSeq[string]()) + check(largeData.findAll(expression) == newSeq[string]()) diff --git a/tests/stdlib/tnativesockets.nim b/tests/stdlib/tnativesockets.nim new file mode 100644 index 000000000..c683647bc --- /dev/null +++ b/tests/stdlib/tnativesockets.nim @@ -0,0 +1,8 @@ +import nativesockets, unittest + +suite "nativesockets": + test "getHostname": + let hostname = getHostname() + check hostname.len > 0 + check hostname.len < 64 + diff --git a/web/question.rst b/web/question.rst index 9de178c90..54c392ced 100644 --- a/web/question.rst +++ b/web/question.rst @@ -125,7 +125,7 @@ General FAQ What about editor support? -------------------------- - - Nim IDE: https://github.com/nim-lang/Aporia + - Native Nim Editor: https://github.com/nim-lang/Aporia - Visual Studio Code: https://marketplace.visualstudio.com/items?itemName=kosz78.nim - Emacs: https://github.com/nim-lang/nim-mode - Vim: https://github.com/zah/nimrod.vim/ diff --git a/web/website.ini b/web/website.ini index a3a04f01e..f4954a4cb 100644 --- a/web/website.ini +++ b/web/website.ini @@ -8,7 +8,7 @@ Authors: "Andreas Rumpf and contributors" # Underscores are replaced with a space. # Everything after ; is the ID Community: "community.html;link_forum" -Aporia_IDE: "https://github.com/nim-lang/Aporia;link_aporia" +; Aporia_IDE: "https://github.com/nim-lang/Aporia;link_aporia" GitHub_Repo: "http://github.com/nim-lang/Nim;link_github" |