diff options
Diffstat (limited to 'lib/pure')
-rw-r--r-- | lib/pure/asyncdispatch.nim | 4 | ||||
-rw-r--r-- | lib/pure/asynchttpserver.nim | 2 | ||||
-rw-r--r-- | lib/pure/asyncmacro.nim | 41 | ||||
-rw-r--r-- | lib/pure/asyncnet.nim | 6 | ||||
-rw-r--r-- | lib/pure/collections/tables.nim | 7 | ||||
-rw-r--r-- | lib/pure/concurrency/cpuinfo.nim | 2 | ||||
-rw-r--r-- | lib/pure/distros.nim | 2 | ||||
-rw-r--r-- | lib/pure/hashes.nim | 11 | ||||
-rw-r--r-- | lib/pure/httpclient.nim | 3 | ||||
-rw-r--r-- | lib/pure/includes/asynccommon.nim | 2 | ||||
-rw-r--r-- | lib/pure/json.nim | 23 | ||||
-rw-r--r-- | lib/pure/math.nim | 36 | ||||
-rw-r--r-- | lib/pure/os.nim | 46 | ||||
-rw-r--r-- | lib/pure/ospaths.nim | 9 | ||||
-rw-r--r-- | lib/pure/osproc.nim | 5 | ||||
-rw-r--r-- | lib/pure/parsecfg.nim | 4 | ||||
-rw-r--r-- | lib/pure/parseopt.nim | 45 | ||||
-rw-r--r-- | lib/pure/parseopt2.nim | 45 | ||||
-rw-r--r-- | lib/pure/pegs.nim | 2 | ||||
-rw-r--r-- | lib/pure/random.nim | 3 | ||||
-rw-r--r-- | lib/pure/streams.nim | 4 | ||||
-rw-r--r-- | lib/pure/strutils.nim | 4 | ||||
-rw-r--r-- | lib/pure/times.nim | 100 |
23 files changed, 259 insertions, 147 deletions
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 1697384e0..8c1cf6b18 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -163,8 +163,8 @@ include includes/asyncfutures type PDispatcherBase = ref object of RootRef - timers: HeapQueue[tuple[finishAt: float, fut: Future[void]]] - callbacks: Deque[proc ()] + timers*: HeapQueue[tuple[finishAt: float, fut: Future[void]]] + callbacks*: Deque[proc ()] proc processTimers(p: PDispatcherBase) {.inline.} = #Process just part if timers at a step diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 8d059dbbc..a374e80e8 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -127,7 +127,7 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] = i.inc protocol.parseInt(result.minor, i) proc sendStatus(client: AsyncSocket, status: string): Future[void] = - client.send("HTTP/1.1 " & status & "\c\L") + client.send("HTTP/1.1 " & status & "\c\L\c\L") proc processClient(client: AsyncSocket, address: string, callback: proc (request: Request): diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index ce4c9a9c9..89b216b25 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -301,13 +301,13 @@ proc verifyReturnType(typeName: string) {.compileTime.} = proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = ## This macro transforms a single procedure into a closure iterator. ## The ``async`` macro supports a stmtList holding multiple async procedures. - if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef}: + if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}: error("Cannot transform this node kind into an async proc." & " proc/method definition or lambda node expected.") - hint("Processing " & prc[0].getName & " as an async proc.") + let prcName = prc.name.getName - let returnType = prc[3][0] + let returnType = prc.params[0] var baseType: NimNode # Verify that the return type is a Future[T] if returnType.kind == nnkBracketExpr: @@ -326,9 +326,9 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = let subtypeIsVoid = returnType.kind == nnkEmpty or (baseType.kind == nnkIdent and returnType[1].ident == !"void") - let futureVarIdents = getFutureVarIdents(prc[3]) + let futureVarIdents = getFutureVarIdents(prc.params) - var outerProcBody = newNimNode(nnkStmtList, prc[6]) + var outerProcBody = newNimNode(nnkStmtList, prc.body) # -> var retFuture = newFuture[T]() var retFutureSym = genSym(nskVar, "retFuture") @@ -338,10 +338,10 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = outerProcBody.add( newVarStmt(retFutureSym, newCall( - newNimNode(nnkBracketExpr, prc[6]).add( + newNimNode(nnkBracketExpr, prc.body).add( newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`. subRetType), - newLit(prc[0].getName)))) # Get type from return type of this proc + newLit(prcName)))) # Get type from return type of this proc # -> iterator nameIter(): FutureBase {.closure.} = # -> {.push warning[resultshadowed]: off.} @@ -349,8 +349,8 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = # -> {.pop.} # -> <proc_body> # -> complete(retFuture, result) - var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter") - var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, + var iteratorNameSym = genSym(nskIterator, $prcName & "Iter") + var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid, futureVarIdents, nil) # don't do anything with forward bodies (empty) if procBody.kind != nnkEmpty: @@ -362,7 +362,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = newIdentNode("warning"), newIdentNode("resultshadowed")), newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.} - procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add( + procBody.insert(1, newNimNode(nnkVarSection, prc.body).add( newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T procBody.insert(2, newNimNode(nnkPragma).add( @@ -377,35 +377,32 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")], procBody, nnkIteratorDef) - closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure")) + closureIterator.pragma = newNimNode(nnkPragma, lineInfoFrom=prc.body) + closureIterator.addPragma(newIdentNode("closure")) + closureIterator.addPragma(newIdentNode("gcsafe")) outerProcBody.add(closureIterator) # -> createCb(retFuture) #var cbName = newIdentNode("cb") var procCb = getAst createCb(retFutureSym, iteratorNameSym, - newStrLitNode(prc[0].getName), + newStrLitNode(prcName), createFutureVarCompletions(futureVarIdents, nil)) outerProcBody.add procCb # -> return retFuture - outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym) + outerProcBody.add newNimNode(nnkReturnStmt, prc.body[^1]).add(retFutureSym) result = prc - # Remove the 'async' pragma. - for i in 0 .. <result[4].len: - if result[4][i].kind == nnkIdent and result[4][i].ident == !"async": - result[4].del(i) - result[4] = newEmptyNode() if subtypeIsVoid: # Add discardable pragma. if returnType.kind == nnkEmpty: # Add Future[void] - result[3][0] = parseExpr("Future[void]") + result.params[0] = parseExpr("Future[void]") if procBody.kind != nnkEmpty: - result[6] = outerProcBody + result.body = outerProcBody #echo(treeRepr(result)) - #if prc[0].getName == "recvLineInto": + #if prcName == "recvLineInto": # echo(toStrLit(result)) macro async*(prc: untyped): untyped = @@ -529,8 +526,6 @@ macro multisync*(prc: untyped): untyped = ## ## The generated async procedures use the ``async`` macro, whereas the ## generated synchronous procedures simply strip off the ``await`` calls. - hint("Processing " & prc[0].getName & " as a multisync proc.") - let (sync, asyncPrc) = splitProc(prc) result = newStmtList() result.add(asyncSingleProc(asyncPrc)) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 9f73bc3cf..5de65efe0 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -533,15 +533,13 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string], else: var c = "" while true: - let recvFut = recv(socket, 1, flags) - c = recvFut.read() + c = await recv(socket, 1, flags) if c.len == 0: resString.mget.setLen(0) resString.complete() return if c == "\r": - let recvFut = recv(socket, 1, flags) # Skip \L - c = recvFut.read() + c = await recv(socket, 1, flags) # Skip \L assert c == "\L" addNLIfEmpty() resString.complete() diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 323af5a38..5b6701a12 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -590,8 +590,11 @@ proc enlarge[A, B](t: var OrderedTable[A, B]) = swap(t.data, n) while h >= 0: var nxt = n[h].next - if isFilled(n[h].hcode): - var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode) + let eh = n[h].hcode + if isFilled(eh): + var j: Hash = eh and maxHash(t) + while isFilled(t.data[j].hcode): + j = nextTry(j, maxHash(t)) rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j) h = nxt diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index c3390573a..603fee080 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -69,4 +69,4 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = result = affinitySpaceTotal().int else: result = sysconf(SC_NPROCESSORS_ONLN) - if result <= 0: result = 1 + if result <= 0: result = 0 diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index 896497630..0adba5b1e 100644 --- a/lib/pure/distros.nim +++ b/lib/pure/distros.nim @@ -158,7 +158,7 @@ proc detectOsImpl(d: Distribution): bool = of Distribution.ArchLinux: result = "arch" in toLowerAscii(uname()) of Distribution.OpenSUSE: - result = "suse" in toLowerAscii(uname()) + result = "suse" in toLowerAscii(uname()) or "suse" in toLowerAscii(release()) of Distribution.GoboLinux: result = "-Gobo " in uname() of Distribution.OpenMandriva: diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index e8c8776c6..b015ed311 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -139,9 +139,14 @@ proc hash*(x: cstring): Hash = ## efficient hashing of null-terminated strings var h: Hash = 0 var i = 0 - while x[i] != 0.char: - h = h !& ord(x[i]) - inc i + when defined(js): + while i < x.len: + h = h !& ord(x[i]) + inc i + else: + while x[i] != 0.char: + h = h !& ord(x[i]) + inc i result = !$h proc hash*(sBuf: string, sPos, ePos: int): Hash = diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 4f43177a8..909a2613f 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -62,7 +62,8 @@ ## let body = %*{ ## "data": "some text" ## } -## echo client.request("http://some.api", httpMethod = HttpPost, body = $body) +## let response = client.request("http://some.api", httpMethod = HttpPost, body = $body) +## echo response.status ## ## Progress reporting ## ================== diff --git a/lib/pure/includes/asynccommon.nim b/lib/pure/includes/asynccommon.nim index a7d2f803f..8b760c66a 100644 --- a/lib/pure/includes/asynccommon.nim +++ b/lib/pure/includes/asynccommon.nim @@ -3,7 +3,7 @@ template newAsyncNativeSocketImpl(domain, sockType, protocol) = if handle == osInvalidSocket: raiseOSError(osLastError()) handle.setBlocking(false) - when defined(macosx): + when defined(macosx) and not defined(nimdoc): handle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1) result = handle.AsyncFD register(result) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 564f952d3..e3d5191c6 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1001,7 +1001,7 @@ proc escapeJson*(s: string; result: var string) = result.add("\"") for x in runes(s): var r = int(x) - if r >= 32 and r <= 127: + if r >= 32 and r <= 126: var c = chr(r) case c of '"': result.add("\\\"") @@ -1608,7 +1608,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode = result = processType(newIdentNode(typeName), obj, jsonNode, true) of "seq": let seqT = typeSym[1] - let forLoopI = newIdentNode("i") + let forLoopI = genSym(nskForVar, "i") let indexerNode = createJsonIndexer(jsonNode, forLoopI) let constructorNode = createConstructor(seqT, indexerNode) @@ -1616,12 +1616,25 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode = result = quote do: ( var list: `typeSym` = @[]; - # if `jsonNode`.kind != JArray: - # # TODO: Improve error message. - # raise newException(ValueError, "Expected a list") + verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`)); for `forLoopI` in 0 .. <`jsonNode`.len: list.add(`constructorNode`); list ) + of "array": + let arrayT = typeSym[2] + let forLoopI = genSym(nskForVar, "i") + let indexerNode = createJsonIndexer(jsonNode, forLoopI) + let constructorNode = createConstructor(arrayT, indexerNode) + + # Create a statement expression containing a for loop. + result = quote do: + ( + var list: `typeSym`; + verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`)); + for `forLoopI` in 0 .. <`jsonNode`.len: list[`forLoopI`] =`constructorNode`; + list + ) + else: # Generic type. let obj = getType(typeSym) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index a8432b6f0..8037b31b0 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -235,7 +235,7 @@ when not defined(JS): x = x and (not (1'u64 shl (64'u64-12'u64-e) - 1'u64)) result = cast[float64](x) - + proc truncImpl(f: float32): float32 = const mask : uint32 = 0xFF @@ -255,7 +255,7 @@ when not defined(JS): x = x and (not (1'u32 shl (32'u32-9'u32-e) - 1'u32)) result = cast[float32](x) - + proc trunc*(x: float64): float64 = if classify(x) in {fcZero, fcNegZero, fcNan, fcInf, fcNegInf}: return x result = truncImpl(x) @@ -395,6 +395,12 @@ proc radToDeg*[T: float32|float64](d: T): T {.inline.} = ## Convert from radians to degrees result = T(d) / RadPerDeg +proc sgn*[T: SomeNumber](x: T): int {.inline.} = + ## Sign function. Returns -1 for negative numbers and `NegInf`, 1 for + ## positive numbers and `Inf`, and 0 for positive zero, negative zero and + ## `NaN`. + ord(T(0) < x) - ord(x < T(0)) + proc `mod`*[T: float32|float64](x, y: T): T = ## Computes the modulo operation for float operators. Equivalent ## to ``x - y * floor(x/y)``. Note that the remainder will always @@ -407,10 +413,13 @@ proc `mod`*[T: float32|float64](x, y: T): T = {.pop.} {.pop.} -proc `^`*[T](x, y: T): T = +proc `^`*[T](x: T, y: Natural): T = ## Computes ``x`` to the power ``y`. ``x`` must be non-negative, use ## `pow <#pow,float,float>` for negative exponents. - assert y >= T(0) + when compiles(y >= T(0)): + assert y >= T(0) + else: + assert T(y) >= T(0) var (x, y) = (x, y) result = 1 @@ -447,6 +456,7 @@ when isMainModule and not defined(JS): assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0 assert(erf(6.0) > erf(5.0)) assert(erfc(6.0) < erfc(5.0)) + when isMainModule: # Function for approximate comparison of floats proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9) @@ -509,3 +519,21 @@ when isMainModule: doAssert(classify(trunc(-1e1000000'f32)) == fcNegInf) doAssert(classify(trunc(f_nan.float32)) == fcNan) doAssert(classify(trunc(0.0'f32)) == fcZero) + + block: # sgn() tests + assert sgn(1'i8) == 1 + assert sgn(1'i16) == 1 + assert sgn(1'i32) == 1 + assert sgn(1'i64) == 1 + assert sgn(1'u8) == 1 + assert sgn(1'u16) == 1 + assert sgn(1'u32) == 1 + assert sgn(1'u64) == 1 + assert sgn(-12342.8844'f32) == -1 + assert sgn(123.9834'f64) == 1 + assert sgn(0'i32) == 0 + assert sgn(0'f32) == 0 + assert sgn(NegInf) == -1 + assert sgn(Inf) == 1 + assert sgn(NaN) == 0 + diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 98b6aa309..f7bcfb60e 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -666,29 +666,38 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} else: raiseOSError(osLastError(), $strerror(errno)) -proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", - tags: [ReadIOEffect, WriteIOEffect].} = - ## Moves a file from `source` to `dest`. If this fails, `OSError` is raised. +proc tryMoveFSObject(source, dest: string): bool = + ## Moves a file or directory from `source` to `dest`. Returns false in case + ## of `EXDEV` error. In case of other errors `OSError` is raised. Returns + ## true in case of success. when defined(Windows): when useWinUnicode: let s = newWideCString(source) let d = newWideCString(dest) - if moveFileW(s, d) == 0'i32: raiseOSError(osLastError()) + if moveFileExW(s, d, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError()) else: - if moveFileA(source, dest) == 0'i32: raiseOSError(osLastError()) + if moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError()) else: if c_rename(source, dest) != 0'i32: let err = osLastError() if err == EXDEV.OSErrorCode: - # Fallback to copy & del - copyFile(source, dest) - try: - removeFile(source) - except: - discard tryRemoveFile(dest) - raise + return false else: raiseOSError(err, $strerror(errno)) + return true + +proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", + tags: [ReadIOEffect, WriteIOEffect].} = + ## Moves a file from `source` to `dest`. If this fails, `OSError` is raised. + if not tryMoveFSObject(source, dest): + when not defined(windows): + # Fallback to copy & del + copyFile(source, dest) + try: + removeFile(source) + except: + discard tryRemoveFile(dest) + raise proc execShellCmd*(command: string): int {.rtl, extern: "nos$1", tags: [ExecIOEffect].} = @@ -1369,6 +1378,14 @@ proc exclFilePermissions*(filename: string, ## setFilePermissions(filename, getFilePermissions(filename)-permissions) setFilePermissions(filename, getFilePermissions(filename)-permissions) +proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect].} = + ## Moves a directory from `source` to `dest`. If this fails, `OSError` is raised. + if not tryMoveFSObject(source, dest): + when not defined(windows): + # Fallback to copy & del + copyDir(source, dest) + removeDir(source) + include ospaths proc expandSymlink*(symlinkPath: string): string = @@ -1412,7 +1429,7 @@ when defined(nimdoc): proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = ## Returns the `i`-th `command line argument`:idx: given to the application. ## - ## `i` should be in the range `1..paramCount()`, the `EInvalidIndex` + ## `i` should be in the range `1..paramCount()`, the `IndexError` ## exception will be raised for invalid values. Instead of iterating over ## `paramCount() <#paramCount>`_ with this proc you can call the ## convenience `commandLineParams() <#commandLineParams>`_. @@ -1450,7 +1467,8 @@ elif defined(windows): tags: [ReadIOEffect].} = # Docstring in nimdoc block. if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine()) - return TaintedString(ownArgv[i]) + if i < ownArgv.len and i >= 0: return TaintedString(ownArgv[i]) + raise newException(IndexError, "invalid index") elif not defined(createNimRtl) and not(defined(posix) and appType == "lib") and diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index 7720fb2a6..fa5342fcf 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -516,7 +516,16 @@ when declared(getEnv) or defined(nimscript): proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} = ## Returns the config directory of the current user for applications. + ## + ## On non-Windows OSs, this proc conforms to the XDG Base Directory + ## spec. Thus, this proc returns the value of the XDG_CONFIG_DIR environment + ## variable if it is set, and returns the default configuration directory, + ## "~/.config/", otherwise. + ## + ## An OS-dependent trailing slash is always present at the end of the + ## returned string; `\\` on Windows and `/` on all other OSs. when defined(windows): return string(getEnv("APPDATA")) & "\\" + elif getEnv("XDG_CONFIG_DIR"): return string(getEnv("XDG_CONFIG_DIR")) & "/" else: return string(getEnv("HOME")) & "/.config/" proc getTempDir*(): string {.rtl, extern: "nos$1", diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index c94a65a63..23c8546c4 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -863,18 +863,15 @@ elif not defined(useNimRtl): if data.workingDir.len > 0: setCurrentDir($data.workingDir) var pid: Pid - var err: OSErrorCode if data.optionPoUsePath: res = posix_spawnp(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv) - if res != 0'i32: err = osLastError() else: res = posix_spawn(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv) - if res != 0'i32: err = osLastError() discard posix_spawn_file_actions_destroy(fops) discard posix_spawnattr_destroy(attr) - if res != 0'i32: raiseOSError(err) + if res != 0'i32: raiseOSError(OSErrorCode(res)) return pid else: diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 28681a11f..5bdd3bc40 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -540,8 +540,8 @@ proc writeConfig*(dict: Config, filename: string) = ## Writes the contents of the table to the specified configuration file. ## Note: Comment statement will be ignored. let file = open(filename, fmWrite) - let fileStream = newFileStream(filename) - defer: fileStream.close() + defer: file.close() + let fileStream = newFileStream(file) dict.writeConfig(fileStream) proc getSectionValue*(dict: Config, section, key: string): string = diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index 218f5ab81..23568edb9 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -149,26 +149,41 @@ proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} = ## retrieves the rest of the command line that has not been parsed yet. result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString +iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedString] = + ## This is an convenience iterator for iterating over the given OptParser object. + ## Example: + ## + ## .. code-block:: nim + ## var p = initOptParser("--left --debug:3 -l=4 -r:2") + ## for kind, key, val in p.getopt(): + ## case kind + ## of cmdArgument: + ## filename = key + ## of cmdLongOption, cmdShortOption: + ## case key + ## of "help", "h": writeHelp() + ## of "version", "v": writeVersion() + ## of cmdEnd: assert(false) # cannot happen + ## if filename == "": + ## # no filename has been given, so we show the help: + ## writeHelp() + p.pos = 0 + while true: + next(p) + if p.kind == cmdEnd: break + yield (p.kind, p.key, p.val) + when declared(initOptParser): iterator getopt*(): tuple[kind: CmdLineKind, key, val: TaintedString] = - ## This is an convenience iterator for iterating over the command line. - ## This uses the OptParser object. Example: + ## This is an convenience iterator for iterating over the command line arguments. + ## This create a new OptParser object. + ## See above for a more detailed example ## ## .. code-block:: nim - ## var - ## filename = "" ## for kind, key, val in getopt(): - ## case kind - ## of cmdArgument: - ## filename = key - ## of cmdLongOption, cmdShortOption: - ## case key - ## of "help", "h": writeHelp() - ## of "version", "v": writeVersion() - ## of cmdEnd: assert(false) # cannot happen - ## if filename == "": - ## # no filename has been given, so we show the help: - ## writeHelp() + ## # this will iterate over all arguments passed to the cmdline. + ## continue + ## var p = initOptParser() while true: next(p) diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim index 7fd9c60fe..2e8dbe140 100644 --- a/lib/pure/parseopt2.nim +++ b/lib/pure/parseopt2.nim @@ -123,26 +123,41 @@ type {.deprecated: [TGetoptResult: GetoptResult].} +iterator getopt*(p: var OptParser): GetoptResult = + ## This is an convenience iterator for iterating over the given OptParser object. + ## Example: + ## + ## .. code-block:: nim + ## var p = initOptParser("--left --debug:3 -l=4 -r:2") + ## for kind, key, val in p.getopt(): + ## case kind + ## of cmdArgument: + ## filename = key + ## of cmdLongOption, cmdShortOption: + ## case key + ## of "help", "h": writeHelp() + ## of "version", "v": writeVersion() + ## of cmdEnd: assert(false) # cannot happen + ## if filename == "": + ## # no filename has been given, so we show the help: + ## writeHelp() + p.pos = 0 + while true: + next(p) + if p.kind == cmdEnd: break + yield (p.kind, p.key, p.val) + when declared(paramCount): iterator getopt*(): GetoptResult = - ## This is an convenience iterator for iterating over the command line. - ## This uses the OptParser object. Example: + ## This is an convenience iterator for iterating over the command line arguments. + ## This create a new OptParser object. + ## See above for a more detailed example ## ## .. code-block:: nim - ## var - ## filename = "" ## for kind, key, val in getopt(): - ## case kind - ## of cmdArgument: - ## filename = key - ## of cmdLongOption, cmdShortOption: - ## case key - ## of "help", "h": writeHelp() - ## of "version", "v": writeVersion() - ## of cmdEnd: assert(false) # cannot happen - ## if filename == "": - ## # no filename has been given, so we show the help: - ## writeHelp() + ## # this will iterate over all arguments passed to the cmdline. + ## continue + ## var p = initOptParser() while true: next(p) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 5c978a2f8..6a52e2cd5 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -371,7 +371,7 @@ proc esc(c: char, reserved = {'\0'..'\255'}): string = of '\a': result = "\\a" of '\\': result = "\\\\" of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c - elif c < ' ' or c >= '\128': result = '\\' & $ord(c) + elif c < ' ' or c >= '\127': result = '\\' & $ord(c) elif c in reserved: result = '\\' & c else: result = $c diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 1f750edcd..8a32f7d9a 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -123,7 +123,8 @@ when not defined(nimscript): proc getMil(t: Time): int {.importcpp: "getTime", nodecl.} randomize(getMil times.getTime()) else: - randomize(int times.getTime()) + let time = int(times.epochTime() * 1_000_000_000) + randomize(time) {.pop.} diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index eea06f4ce..438b48beb 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -334,12 +334,16 @@ when not defined(js): if result > 0: copyMem(buffer, addr(s.data[s.pos]), result) inc(s.pos, result) + else: + result = 0 proc ssPeekData(s: Stream, buffer: pointer, bufLen: int): int = var s = StringStream(s) result = min(bufLen, s.data.len - s.pos) if result > 0: copyMem(buffer, addr(s.data[s.pos]), result) + else: + result = 0 proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) = var s = StringStream(s) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 458c22f3a..20b2657f6 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1643,7 +1643,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, ## * replaces any ``\`` by ``\\`` ## * replaces any ``'`` by ``\'`` ## * replaces any ``"`` by ``\"`` - ## * replaces any other character in the set ``{'\0'..'\31', '\128'..'\255'}`` + ## * replaces any other character in the set ``{'\0'..'\31', '\127'..'\255'}`` ## by ``\xHH`` where ``HH`` is its hexadecimal value. ## The procedure has been designed so that its output is usable for many ## different common syntaxes. The resulting string is prefixed with @@ -1653,7 +1653,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, result.add(prefix) for c in items(s): case c - of '\0'..'\31', '\128'..'\255': + of '\0'..'\31', '\127'..'\255': add(result, "\\x") add(result, toHex(ord(c), 2)) of '\\': add(result, "\\\\") diff --git a/lib/pure/times.nim b/lib/pure/times.nim index bad003a3e..1bda94d14 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -81,7 +81,7 @@ when defined(posix) and not defined(JS): elif defined(windows): import winlean - when defined(vcc) or defined(bcc): + when defined(vcc) or defined(bcc) or defined(icl): # newest version of Visual C++ defines time_t to be of 64 bits type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64 # visual c's c runtime exposes these under a different name @@ -98,46 +98,47 @@ elif defined(windows): elif defined(JS): type - Time* = ref TimeObj - TimeObj {.importc.} = object - 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: [], noSideEffect, 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.} + TimeBase = float + Time* = distinct TimeBase + + proc getDay(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getFullYear(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getHours(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getMilliseconds(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getMinutes(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getMonth(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getSeconds(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getTime(t: Time): int {.tags: [], raises: [], noSideEffect, benign, importcpp.} + proc getTimezoneOffset(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getDate(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getUTCDate(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getUTCFullYear(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getUTCHours(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getUTCMilliseconds(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getUTCMinutes(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getUTCMonth(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getUTCSeconds(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getUTCDay(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc getYear(t: Time): int {.tags: [], raises: [], benign, importcpp.} + proc parse(t: Time; s: cstring): Time {.tags: [], raises: [], benign, importcpp.} + proc setDate(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setFullYear(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setHours(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setMilliseconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setMinutes(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setMonth(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setSeconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setTime(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setUTCDate(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setUTCFullYear(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setUTCHours(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setUTCMilliseconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setUTCMinutes(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setUTCMonth(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setUTCSeconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc setYear(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.} + proc toGMTString(t: Time): cstring {.tags: [], raises: [], benign, importcpp.} + proc toLocaleString(t: Time): cstring {.tags: [], raises: [], benign, importcpp.} type TimeInfo* = object of RootObj ## represents a time in different parts @@ -225,17 +226,26 @@ proc `-`*(a, b: Time): int64 {. proc `<`*(a, b: Time): bool {. rtl, extern: "ntLtTime", tags: [], raises: [], noSideEffect.} = ## returns true iff ``a < b``, that is iff a happened before b. - result = a - b < 0 + when defined(js): + result = TimeBase(a) < TimeBase(b) + else: + result = a - b < 0 proc `<=` * (a, b: Time): bool {. rtl, extern: "ntLeTime", tags: [], raises: [], noSideEffect.}= ## returns true iff ``a <= b``. - result = a - b <= 0 + when defined(js): + result = TimeBase(a) <= TimeBase(b) + else: + result = a - b <= 0 proc `==`*(a, b: Time): bool {. rtl, extern: "ntEqTime", tags: [], raises: [], noSideEffect.} = ## returns true if ``a == b``, that is if both times represent the same value - result = a - b == 0 + when defined(js): + result = TimeBase(a) == TimeBase(b) + else: + result = a - b == 0 proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign.} ## returns the offset of the local (non-DST) timezone in seconds west of UTC. @@ -479,7 +489,7 @@ proc `-=`*(t: var Time, ti: TimeInterval) = t = toTime(getLocalTime(t) - ti) proc `-`*(t: Time, ti: TimeInterval): Time = - ## adds the interval `ti` to Time `t` + ## subtracts the interval `ti` from Time `t` ## ## ``echo getTime() - 1.day`` result = toTime(getLocalTime(t) - ti) |