diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2017-07-13 04:48:22 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2017-07-13 04:48:22 +0200 |
commit | 2b862b74e0b0b7b4a18f4262356289fb921eaf0c (patch) | |
tree | 8f41b7355f6d791d6485e8225d6a5cb2f80ca7d6 /lib | |
parent | a5695c13afabac6e67ff677d564b6d1a6aeb1af4 (diff) | |
parent | 0c271f54208c7ba0bac6ad2da87f60e7c6d8e37c (diff) | |
download | Nim-2b862b74e0b0b7b4a18f4262356289fb921eaf0c.tar.gz |
Merge branch 'devel' into araq
Diffstat (limited to 'lib')
42 files changed, 622 insertions, 226 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 83776f16b..af1e9de28 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -225,7 +225,13 @@ proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect.} proc `strVal=`*(n: NimNode, val: string) {.magic: "NSetStrVal", noSideEffect.} proc newNimNode*(kind: NimNodeKind, - n: NimNode=nil): NimNode {.magic: "NNewNimNode", noSideEffect.} + lineInfoFrom: NimNode=nil): NimNode + {.magic: "NNewNimNode", noSideEffect.} + ## Creates a new AST node of the specified kind. + ## + ## The ``lineInfoFrom`` parameter is used for line information when the + ## produced code crashes. You should ensure that it is set to a node that + ## you are transforming. proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.} proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.} @@ -249,6 +255,11 @@ proc newStrLitNode*(s: string): NimNode {.compileTime, noSideEffect.} = result = newNimNode(nnkStrLit) result.strVal = s +proc newCommentStmtNode*(s: string): NimNode {.compileTime, noSideEffect.} = + ## creates a comment statement node + result = newNimNode(nnkCommentStmt) + result.strVal = s + proc newIntLitNode*(i: BiggestInt): NimNode {.compileTime.} = ## creates a int literal node from `i` result = newNimNode(nnkIntLit) @@ -269,6 +280,7 @@ proc newIdentNode*(i: string): NimNode {.compileTime.} = result = newNimNode(nnkIdent) result.ident = !i + type BindSymRule* = enum ## specifies how ``bindSym`` behaves brClosed, ## only the symbols in current scope are bound @@ -426,20 +438,105 @@ proc newLit*(c: char): NimNode {.compileTime.} = result = newNimNode(nnkCharLit) result.intVal = ord(c) -proc newLit*(i: BiggestInt): NimNode {.compileTime.} = + +proc newLit*(i: int): NimNode {.compileTime.} = ## produces a new integer literal node. result = newNimNode(nnkIntLit) result.intVal = i +proc newLit*(i: int8): NimNode {.compileTime.} = + ## produces a new integer literal node. + result = newNimNode(nnkInt8Lit) + result.intVal = i + +proc newLit*(i: int16): NimNode {.compileTime.} = + ## produces a new integer literal node. + result = newNimNode(nnkInt16Lit) + result.intVal = i + +proc newLit*(i: int32): NimNode {.compileTime.} = + ## produces a new integer literal node. + result = newNimNode(nnkInt32Lit) + result.intVal = i + +proc newLit*(i: int64): NimNode {.compileTime.} = + ## produces a new integer literal node. + result = newNimNode(nnkInt64Lit) + result.intVal = i + +proc newLit*(i: uint): NimNode {.compileTime.} = + ## produces a new unsigned integer literal node. + result = newNimNode(nnkUIntLit) + result.intVal = BiggestInt(i) + +proc newLit*(i: uint8): NimNode {.compileTime.} = + ## produces a new unsigned integer literal node. + result = newNimNode(nnkUInt8Lit) + result.intVal = BiggestInt(i) + +proc newLit*(i: uint16): NimNode {.compileTime.} = + ## produces a new unsigned integer literal node. + result = newNimNode(nnkUInt16Lit) + result.intVal = BiggestInt(i) + +proc newLit*(i: uint32): NimNode {.compileTime.} = + ## produces a new unsigned integer literal node. + result = newNimNode(nnkUInt32Lit) + result.intVal = BiggestInt(i) + +proc newLit*(i: uint64): NimNode {.compileTime.} = + ## produces a new unsigned integer literal node. + result = newNimNode(nnkUInt64Lit) + result.intVal = BiggestInt(i) + proc newLit*(b: bool): NimNode {.compileTime.} = ## produces a new boolean literal node. result = if b: bindSym"true" else: bindSym"false" -proc newLit*(f: BiggestFloat): NimNode {.compileTime.} = +when false: + # the float type is not really a distinct type as described in https://github.com/nim-lang/Nim/issues/5875 + proc newLit*(f: float): NimNode {.compileTime.} = + ## produces a new float literal node. + result = newNimNode(nnkFloatLit) + result.floatVal = f + +proc newLit*(f: float32): NimNode {.compileTime.} = ## produces a new float literal node. - result = newNimNode(nnkFloatLit) + result = newNimNode(nnkFloat32Lit) result.floatVal = f +proc newLit*(f: float64): NimNode {.compileTime.} = + ## produces a new float literal node. + result = newNimNode(nnkFloat64Lit) + result.floatVal = f + +when compiles(float128): + proc newLit*(f: float128): NimNode {.compileTime.} = + ## produces a new float literal node. + result = newNimNode(nnkFloat128Lit) + result.floatVal = f + +proc newLit*(arg: object): NimNode {.compileTime.} = + result = nnkObjConstr.newTree(arg.type.getTypeInst[1]) + for a, b in arg.fieldPairs: + result.add nnkExprColonExpr.newTree( newIdentNode(a), newLit(b) ) + +proc newLit*[N,T](arg: array[N,T]): NimNode {.compileTime.} = + result = nnkBracket.newTree + for x in arg: + result.add newLit(x) + +proc newLit*[T](arg: seq[T]): NimNode {.compileTime.} = + result = nnkBracket.newTree + for x in arg: + result.add newLit(x) + result = nnkPrefix.newTree(bindSym"@", result) + +proc newLit*(arg: tuple): NimNode {.compileTime.} = + result = nnkPar.newTree + for a,b in arg.fieldPairs: + result.add nnkExprColonExpr.newTree( newIdentNode(a), newLit(b) ) + proc newLit*(s: string): NimNode {.compileTime.} = ## produces a new string literal node. result = newNimNode(nnkStrLit) @@ -744,6 +841,8 @@ proc `$`*(node: NimNode): string {.compileTime.} = result = $node[0] of nnkAccQuoted: result = $node[0] + of nnkCommentStmt: + result = node.strVal else: badNodeKind node.kind, "$" diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 02312a4d5..55d1dd2eb 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -79,6 +79,9 @@ const DT_SOCK* = 12 ## UNIX domain socket. DT_WHT* = 14 +# Special types +type Sighandler = proc (a: cint) {.noconv.} + # Platform specific stuff when defined(linux) and defined(amd64): @@ -86,6 +89,9 @@ when defined(linux) and defined(amd64): else: include posix_other +# There used to be this name in posix.nim a long time ago, not sure why! +{.deprecated: [cSIG_HOLD: SIG_HOLD].} + when not defined(macosx): proc st_atime*(s: Stat): Time {.inline.} = ## Second-granularity time of last access @@ -659,7 +665,7 @@ proc sighold*(a1: cint): cint {.importc, header: "<signal.h>".} proc sigignore*(a1: cint): cint {.importc, header: "<signal.h>".} proc siginterrupt*(a1, a2: cint): cint {.importc, header: "<signal.h>".} proc sigismember*(a1: var Sigset, a2: cint): cint {.importc, header: "<signal.h>".} -proc signal*(a1: cint, a2: proc (x: cint) {.noconv.}) {. +proc signal*(a1: cint, a2: Sighandler) {. importc, header: "<signal.h>".} proc sigpause*(a1: cint): cint {.importc, header: "<signal.h>".} proc sigpending*(a1: var Sigset): cint {.importc, header: "<signal.h>".} diff --git a/lib/posix/posix_linux_amd64.nim b/lib/posix/posix_linux_amd64.nim index 70f7e710f..c44128b16 100644 --- a/lib/posix/posix_linux_amd64.nim +++ b/lib/posix/posix_linux_amd64.nim @@ -36,6 +36,9 @@ type {.deprecated: [TSocketHandle: SocketHandle].} +# not detected by detect.nim, guarded by #ifdef __USE_UNIX98 in glibc +const SIG_HOLD* = cast[SigHandler](2) + type Timespec* {.importc: "struct timespec", header: "<time.h>", final, pure.} = object ## struct timespec diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim index 9e2ed32e1..4b693960e 100644 --- a/lib/posix/posix_linux_amd64_consts.nim +++ b/lib/posix/posix_linux_amd64_consts.nim @@ -399,6 +399,9 @@ const SS_ONSTACK* = cint(1) const SS_DISABLE* = cint(2) const MINSIGSTKSZ* = cint(2048) const SIGSTKSZ* = cint(8192) +const SIG_DFL* = cast[Sighandler](0) +const SIG_ERR* = cast[Sighandler](-1) +const SIG_IGN* = cast[Sighandler](1) # <sys/ipc.h> const IPC_CREAT* = cint(512) diff --git a/lib/posix/posix_other_consts.nim b/lib/posix/posix_other_consts.nim index f2a71d1bd..003414a6a 100644 --- a/lib/posix/posix_other_consts.nim +++ b/lib/posix/posix_other_consts.nim @@ -414,6 +414,10 @@ var SS_ONSTACK* {.importc: "SS_ONSTACK", header: "<signal.h>".}: cint var SS_DISABLE* {.importc: "SS_DISABLE", header: "<signal.h>".}: cint var MINSIGSTKSZ* {.importc: "MINSIGSTKSZ", header: "<signal.h>".}: cint var SIGSTKSZ* {.importc: "SIGSTKSZ", header: "<signal.h>".}: cint +var SIG_HOLD* {.importc: "SIG_HOLD", header: "<signal.h>".}: Sighandler +var SIG_DFL* {.importc: "SIG_DFL", header: "<signal.h>".}: Sighandler +var SIG_ERR* {.importc: "SIG_ERR", header: "<signal.h>".}: Sighandler +var SIG_IGN* {.importc: "SIG_IGN", header: "<signal.h>".}: Sighandler # <sys/ipc.h> var IPC_CREAT* {.importc: "IPC_CREAT", header: "<sys/ipc.h>".}: cint 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) diff --git a/lib/system.nim b/lib/system.nim index 9b41253cc..8f653c1e0 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -49,6 +49,9 @@ type cstring* {.magic: Cstring.} ## built-in cstring (*compatible string*) type pointer* {.magic: Pointer.} ## built-in pointer type, use the ``addr`` ## operator to get a pointer to a variable + + typedesc* {.magic: TypeDesc.} ## meta type to denote a type description + const on* = true ## alias for ``true`` off* = false ## alias for ``false`` @@ -56,6 +59,15 @@ const {.push warning[GcMem]: off, warning[Uninit]: off.} {.push hints: off.} +proc `or` *(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.} + ## Constructs an `or` meta class + +proc `and` *(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.} + ## Constructs an `and` meta class + +proc `not` *(a: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.} + ## Constructs an `not` meta class + type Ordinal* {.magic: Ordinal.}[T] ## Generic ordinal type. Includes integer, ## bool, character, and enumeration types @@ -66,11 +78,11 @@ type `ref`* {.magic: Pointer.}[T] ## built-in generic traced pointer type `nil` {.magic: "Nil".} + expr* {.magic: Expr, deprecated.} ## meta type to denote an expression (for templates) - ## **Deprecated** since version 0.15. Use ``untyped`` instead. + ## **Deprecated** since version 0.15. Use ``untyped`` instead. stmt* {.magic: Stmt, deprecated.} ## meta type to denote a statement (for templates) ## **Deprecated** since version 0.15. Use ``typed`` instead. - typedesc* {.magic: TypeDesc.} ## meta type to denote a type description void* {.magic: "VoidType".} ## meta type to denote the absence of any type auto* {.magic: Expr.} ## meta type for automatic type determination any* = distinct auto ## meta type for any supported type @@ -430,6 +442,7 @@ type ## providing an exception message ## is bad style. trace: string + up: ref Exception # used for stacking exceptions. Not exported! SystemError* = object of Exception ## \ ## Abstract class for exceptions that the runtime system raises. @@ -1056,7 +1069,7 @@ proc `div`*[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.} ## ``floor(x/y)``. ## ## .. code-block:: Nim - ## (7 div 5) == 2 + ## (7 div 5) == 1 proc `mod`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ModU", noSideEffect.} ## computes the integer modulo operation (remainder). @@ -1332,6 +1345,7 @@ const hasThreadSupport = compileOption("threads") and not defined(nimscript) hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own taintMode = compileOption("taintmode") + nimEnableCovariance* = defined(nimEnableCovariance) # or true when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"): # tcc doesn't support TLS @@ -1879,7 +1893,7 @@ const NimMajor*: int = 0 ## is the major number of Nim's version. - NimMinor*: int = 16 + NimMinor*: int = 17 ## is the minor number of Nim's version. NimPatch*: int = 1 @@ -2034,6 +2048,14 @@ proc clamp*[T](x, a, b: T): T = if x > b: return b return x +proc len*[T: Ordinal](x: Slice[T]): int {.noSideEffect, inline.} = + ## length of ordinal slice, when x.b < x.a returns zero length + ## + ## .. code-block:: Nim + ## assert((0..5).len == 6) + ## assert((5..2).len == 0) + result = max(0, ord(x.b) - ord(x.a) + 1) + iterator items*[T](a: openArray[T]): T {.inline.} = ## iterates over each item of `a`. var i = 0 @@ -2428,18 +2450,6 @@ when false: # ----------------- GC interface --------------------------------------------- when not defined(nimscript) and hasAlloc: - proc GC_disable*() {.rtl, inl, benign.} - ## disables the GC. If called n-times, n calls to `GC_enable` are needed to - ## reactivate the GC. Note that in most circumstances one should only disable - ## the mark and sweep phase with `GC_disableMarkAndSweep`. - - proc GC_enable*() {.rtl, inl, benign.} - ## enables the GC again. - - proc GC_fullCollect*() {.rtl, benign.} - ## forces a full garbage collection pass. - ## Ordinary code does not need to call this (and should not). - type GC_Strategy* = enum ## the strategy the GC should use for the application gcThroughput, ## optimize for throughput @@ -2449,33 +2459,87 @@ when not defined(nimscript) and hasAlloc: {.deprecated: [TGC_Strategy: GC_Strategy].} - proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.} - ## tells the GC the desired strategy for the application. - ## **Deprecated** since version 0.8.14. This has always been a nop. - - proc GC_enableMarkAndSweep*() {.rtl, benign.} - proc GC_disableMarkAndSweep*() {.rtl, benign.} - ## the current implementation uses a reference counting garbage collector - ## with a seldomly run mark and sweep phase to free cycles. The mark and - ## sweep phase may take a long time and is not needed if the application - ## does not create cycles. Thus the mark and sweep phase can be deactivated - ## and activated separately from the rest of the GC. - - proc GC_getStatistics*(): string {.rtl, benign.} - ## returns an informative string about the GC's activity. This may be useful - ## for tweaking. - - 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", 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`. + when not defined(JS): + proc GC_disable*() {.rtl, inl, benign.} + ## disables the GC. If called n-times, n calls to `GC_enable` are needed to + ## reactivate the GC. Note that in most circumstances one should only disable + ## the mark and sweep phase with `GC_disableMarkAndSweep`. + + proc GC_enable*() {.rtl, inl, benign.} + ## enables the GC again. + + proc GC_fullCollect*() {.rtl, benign.} + ## forces a full garbage collection pass. + ## Ordinary code does not need to call this (and should not). + + proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.} + ## tells the GC the desired strategy for the application. + ## **Deprecated** since version 0.8.14. This has always been a nop. + + proc GC_enableMarkAndSweep*() {.rtl, benign.} + proc GC_disableMarkAndSweep*() {.rtl, benign.} + ## the current implementation uses a reference counting garbage collector + ## with a seldomly run mark and sweep phase to free cycles. The mark and + ## sweep phase may take a long time and is not needed if the application + ## does not create cycles. Thus the mark and sweep phase can be deactivated + ## and activated separately from the rest of the GC. + + proc GC_getStatistics*(): string {.rtl, benign.} + ## returns an informative string about the GC's activity. This may be useful + ## for tweaking. + + 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", 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`. + + else: + template GC_disable* = + {.warning: "GC_disable is a no-op in JavaScript".} + + template GC_enable* = + {.warning: "GC_enable is a no-op in JavaScript".} + + template GC_fullCollect* = + {.warning: "GC_fullCollect is a no-op in JavaScript".} + + template GC_setStrategy* = + {.warning: "GC_setStrategy is a no-op in JavaScript".} + + template GC_enableMarkAndSweep* = + {.warning: "GC_enableMarkAndSweep is a no-op in JavaScript".} + + template GC_disableMarkAndSweep* = + {.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".} + + template GC_ref*[T](x: ref T) = + {.warning: "GC_ref is a no-op in JavaScript".} + + template GC_ref*[T](x: seq[T]) = + {.warning: "GC_ref is a no-op in JavaScript".} + + template GC_ref*(x: string) = + {.warning: "GC_ref is a no-op in JavaScript".} + + template GC_unref*[T](x: ref T) = + {.warning: "GC_unref is a no-op in JavaScript".} + + template GC_unref*[T](x: seq[T]) = + {.warning: "GC_unref is a no-op in JavaScript".} + + template GC_unref*(x: string) = + {.warning: "GC_unref is a no-op in JavaScript".} + + template GC_getStatistics*(): string = + {.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".} + "" template accumulateResult*(iter: untyped) = ## helps to convert an iterator to a proc. @@ -3210,16 +3274,6 @@ when not defined(JS): #and not defined(nimscript): elif defined(JS): # Stubs: - proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = discard - - proc GC_disable() = discard - proc GC_enable() = discard - proc GC_fullCollect() = discard - proc GC_setStrategy(strategy: GC_Strategy) = discard - proc GC_enableMarkAndSweep() = discard - proc GC_disableMarkAndSweep() = discard - proc GC_getStatistics(): string = return "" - proc getOccupiedMem(): int = return -1 proc getFreeMem(): int = return -1 proc getTotalMem(): int = return -1 @@ -3458,7 +3512,7 @@ proc `*=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {. proc `+=`*[T: float|float32|float64] (x: var T, y: T) {. inline, noSideEffect.} = - ## Increments in placee a floating point number + ## Increments in place a floating point number x = x + y proc `-=`*[T: float|float32|float64] (x: var T, y: T) {. @@ -3721,7 +3775,8 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} = when hasAlloc and not defined(nimscript) and not defined(JS): proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} = - ## performs a deep copy of `x`. This is also used by the code generator + ## performs a deep copy of `y` and copies it into `x`. + ## This is also used by the code generator ## for the implementation of ``spawn``. discard diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index bcbc5d92f..78db96e77 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -9,7 +9,6 @@ # Low level allocator for Nim. Has been designed to support the GC. # TODO: -# - eliminate "used" field # - make searching for block O(1) {.push profiler:off.} diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 55f283d2d..6c163f711 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -90,12 +90,11 @@ proc popSafePoint {.compilerRtl, inl.} = excHandler = excHandler.prev proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} = - #if e.parent.isNil: - # e.parent = currException + e.up = currException currException = e proc popCurrentException {.compilerRtl, inl.} = - currException = nil # currException.parent + currException = currException.up # some platforms have native support for stack traces: const @@ -247,6 +246,18 @@ when false: pushCurrentException(e) c_longjmp(excHandler.context, 1) +var onUnhandledException*: (proc (errorMsg: string) {. + nimcall.}) ## set this error \ + ## handler to override the existing behaviour on an unhandled exception. + ## The default is to write a stacktrace to ``stderr`` and then call ``quit(1)``. + ## Unstable API. + +template unhandled(buf, body) = + if onUnhandledException != nil: + onUnhandledException($buf) + else: + body + proc raiseExceptionAux(e: ref Exception) = if localRaiseHook != nil: if not localRaiseHook(e): return @@ -277,7 +288,9 @@ proc raiseExceptionAux(e: ref Exception) = add(buf, " [") add(buf, $e.name) add(buf, "]\n") - showErrorMessage(buf) + unhandled(buf): + showErrorMessage(buf) + quitOrDebug() else: # ugly, but avoids heap allocations :-) template xadd(buf, s, slen: expr) = @@ -293,8 +306,9 @@ proc raiseExceptionAux(e: ref Exception) = add(buf, " [") xadd(buf, e.name, e.name.len) add(buf, "]\n") - showErrorMessage(buf) - quitOrDebug() + unhandled(buf): + showErrorMessage(buf) + quitOrDebug() proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} = if e.name.isNil: e.name = ename diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index b0eb25616..cd03d2a54 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -25,6 +25,13 @@ when defined(nimTypeNames): c_fprintf(stdout, "[Heap] %s: #%ld; bytes: %ld\n", it.name, it.instances, it.sizes) it = it.nextType + when defined(nimGcRefLeak): + proc oomhandler() = + c_fprintf(stdout, "[Heap] ROOTS: #%ld\n", gch.additionalRoots.len) + writeLeaks() + + outOfMemHook = oomhandler + template decTypeSize(cell, t) = # XXX this needs to use atomics for multithreaded apps! when defined(nimTypeNames): diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index 5896af88e..a97e974a1 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -142,11 +142,54 @@ proc doOperation(p: pointer, op: WalkOp) {.benign.} proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.} # we need the prototype here for debugging purposes +when defined(nimGcRefLeak): + const + MaxTraceLen = 20 # tracking the last 20 calls is enough + + type + GcStackTrace = object + lines: array[0..MaxTraceLen-1, cstring] + files: array[0..MaxTraceLen-1, cstring] + + proc captureStackTrace(f: PFrame, st: var GcStackTrace) = + const + firstCalls = 5 + var + it = f + i = 0 + total = 0 + while it != nil and i <= high(st.lines)-(firstCalls-1): + # the (-1) is for the "..." entry + st.lines[i] = it.procname + st.files[i] = it.filename + inc(i) + inc(total) + it = it.prev + var b = it + while it != nil: + inc(total) + it = it.prev + for j in 1..total-i-(firstCalls-1): + if b != nil: b = b.prev + if total != i: + st.lines[i] = "..." + st.files[i] = "..." + inc(i) + while b != nil and i <= high(st.lines): + st.lines[i] = b.procname + st.files[i] = b.filename + inc(i) + b = b.prev + + var ax: array[10_000, GcStackTrace] + proc nimGCref(p: pointer) {.compilerProc.} = # we keep it from being collected by pretending it's not even allocated: when false: when withBitvectors: excl(gch.allocated, usrToCell(p)) else: usrToCell(p).refcount = rcBlack + when defined(nimGcRefLeak): + captureStackTrace(framePtr, ax[gch.additionalRoots.len]) add(gch.additionalRoots, usrToCell(p)) proc nimGCunref(p: pointer) {.compilerProc.} = @@ -157,6 +200,8 @@ proc nimGCunref(p: pointer) {.compilerProc.} = while i >= 0: if d[i] == cell: d[i] = d[L] + when defined(nimGcRefLeak): + ax[i] = ax[L] dec gch.additionalRoots.len break dec(i) @@ -164,6 +209,16 @@ proc nimGCunref(p: pointer) {.compilerProc.} = when withBitvectors: incl(gch.allocated, usrToCell(p)) else: usrToCell(p).refcount = rcWhite +when defined(nimGcRefLeak): + proc writeLeaks() = + for i in 0..gch.additionalRoots.len-1: + c_fprintf(stdout, "[Heap] NEW STACK TRACE\n") + for ii in 0..MaxTraceLen-1: + let line = ax[i].lines[ii] + let file = ax[i].files[ii] + if isNil(line): break + c_fprintf(stdout, "[Heap] %s(%s)\n", file, line) + include gc_common proc prepareDealloc(cell: PCell) = diff --git a/lib/system/gc_stack.nim b/lib/system/gc_stack.nim index 3eda08df9..e7b9f65a7 100644 --- a/lib/system/gc_stack.nim +++ b/lib/system/gc_stack.nim @@ -79,7 +79,7 @@ template withRegion*(r: MemRegion; body: untyped) = try: body finally: - r = tlRegion + #r = tlRegion tlRegion = oldRegion template inc(p: pointer, s: int) = diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 8a81a550a..768f9bc17 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -446,7 +446,7 @@ when defined(kwin): print(buf); """ -elif defined(nodejs): +elif not defined(nimOldEcho): proc ewriteln(x: cstring) = log(x) proc rawEcho {.compilerproc, asmNoStackFrame.} = diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 431f84bfd..5b5ba9490 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -255,12 +255,21 @@ elif defined(gogc): next_gc: uint64 # next GC (in heap_alloc time) last_gc: uint64 # last GC (in absolute time) pause_total_ns: uint64 - pause_ns: array[256, uint64] + pause_ns: array[256, uint64] # circular buffer of recent gc pause lengths + pause_end: array[256, uint64] # circular buffer of recent gc end times (nanoseconds since 1970) numgc: uint32 + numforcedgc: uint32 # number of user-forced GCs + gc_cpu_fraction: float64 # fraction of CPU time used by GC enablegc: cbool debuggc: cbool # Statistics about allocation size classes. by_size: array[goNumSizeClasses, goMStats_inner_struct] + # Statistics below here are not exported to MemStats directly. + tinyallocs: uint64 # number of tiny allocations that didn't cause actual allocation; not exported to go directly + gc_trigger: uint64 + heap_live: uint64 + heap_scan: uint64 + heap_marked: uint64 proc goRuntime_ReadMemStats(a2: ptr goMStats) {.cdecl, importc: "runtime_ReadMemStats", diff --git a/lib/system/repr.nim b/lib/system/repr.nim index d9aa03b53..ab02c58a2 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -49,7 +49,7 @@ proc reprStrAux(result: var string, s: cstring; len: int) = of '"': add result, "\\\"" of '\\': add result, "\\\\" # BUGFIX: forgotten of '\10': add result, "\\10\"\n\"" # " \n " # better readability - of '\128' .. '\255', '\0'..'\9', '\11'..'\31': + of '\127' .. '\255', '\0'..'\9', '\11'..'\31': add result, "\\" & reprInt(ord(c)) else: result.add(c) @@ -68,7 +68,7 @@ proc reprChar(x: char): string {.compilerRtl.} = case x of '"': add result, "\\\"" of '\\': add result, "\\\\" - of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x)) + of '\127' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x)) else: add result, x add result, "\'" diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim index 6b0e32191..5c265a891 100644 --- a/lib/system/reprjs.nim +++ b/lib/system/reprjs.nim @@ -44,7 +44,7 @@ proc reprChar(x: char): string {.compilerRtl.} = case x of '"': add(result, "\\\"") of '\\': add(result, "\\\\") - of '\128'..'\255', '\0'..'\31': add( result, "\\" & reprInt(ord(x)) ) + of '\127'..'\255', '\0'..'\31': add( result, "\\" & reprInt(ord(x)) ) else: add(result, x) add(result, "\'") @@ -56,7 +56,7 @@ proc reprStrAux(result: var string, s: cstring, len: int) = of '"': add(result, "\\\"") of '\\': add(result, "\\\\") of '\10': add(result, "\\10\"\n\"") - of '\128'..'\255', '\0'..'\9', '\11'..'\31': + of '\127'..'\255', '\0'..'\9', '\11'..'\31': add( result, "\\" & reprInt(ord(c)) ) else: add( result, reprInt(ord(c)) ) # Not sure about this. diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim index f61b887ad..6569f4f9f 100644 --- a/lib/system/syslocks.nim +++ b/lib/system/syslocks.nim @@ -117,6 +117,12 @@ else: when defined(linux) and defined(amd64): abi: array[48 div sizeof(clonglong), clonglong] + SysCondAttr {.importc: "pthread_condattr_t", pure, final + header: """#include <sys/types.h> + #include <pthread.h>""".} = object + when defined(linux) and defined(amd64): + abi: array[4 div sizeof(cint), cint] # actually a cint + SysLockType = distinct cint proc initSysLockAux(L: var SysLockObj, attr: ptr SysLockAttr) {. @@ -185,7 +191,7 @@ else: importc: "pthread_mutexattr_settype", header: "<pthread.h>", noSideEffect.} else: - proc initSysCondAux(cond: var SysCondObj, cond_attr: pointer) {. + proc initSysCondAux(cond: var SysCondObj, cond_attr: ptr SysCondAttr = nil) {. importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.} proc deinitSysCondAux(cond: var SysCondObj) {.noSideEffect, importc: "pthread_cond_destroy", header: "<pthread.h>".} @@ -196,7 +202,7 @@ else: importc: "pthread_cond_signal", header: "<pthread.h>", noSideEffect.} when defined(ios): - proc initSysCond(cond: var SysCond, cond_attr: pointer = nil) = + proc initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) = cond = cast[SysCond](c_malloc(sizeof(SysCondObj))) initSysCondAux(cond[], cond_attr) @@ -209,7 +215,7 @@ else: template signalSysCond(cond: var SysCond) = signalSysCondAux(cond[]) else: - template initSysCond(cond: var SysCond, cond_attr: pointer = nil) = + template initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) = initSysCondAux(cond, cond_attr) template deinitSysCond(cond: var SysCond) = deinitSysCondAux(cond) diff --git a/lib/system/threads.nim b/lib/system/threads.nim index d1012e9c5..49b13576c 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -264,7 +264,17 @@ else: proc getThreadId*(): int = result = int(lwp_gettid()) - elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd): + elif defined(openbsd): + proc getthrid(): int32 {.importc: "getthrid", header: "<unistd.h>".} + + proc getThreadId*(): int = + result = int(getthrid()) + elif defined(netbsd): + proc lwp_self(): int32 {.importc: "_lwp_self", header: "<lwp.h>".} + + proc getThreadId*(): int = + result = int(lwp_self()) + elif defined(macosx) or defined(freebsd): proc pthread_threadid_np(y: pointer; x: var uint64): cint {.importc, header: "pthread.h".} proc getThreadId*(): int = diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 164499543..7a221ceb1 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -291,6 +291,14 @@ const FILE_ATTRIBUTE_TEMPORARY* = 256'i32 MAX_PATH* = 260 + + MOVEFILE_COPY_ALLOWED* = 0x2'i32 + MOVEFILE_CREATE_HARDLINK* = 0x10'i32 + MOVEFILE_DELAY_UNTIL_REBOOT* = 0x4'i32 + MOVEFILE_FAIL_IF_NOT_TRACKABLE* = 0x20'i32 + MOVEFILE_REPLACE_EXISTING* = 0x1'i32 + MOVEFILE_WRITE_THROUGH* = 0x8'i32 + type WIN32_FIND_DATA* {.pure.} = object dwFileAttributes*: int32 @@ -342,6 +350,9 @@ when useWinUnicode: proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString): WINBOOL {. importc: "MoveFileW", stdcall, dynlib: "kernel32".} + proc moveFileExW*(lpExistingFileName, lpNewFileName: WideCString, + flags: DWORD): WINBOOL {. + importc: "MoveFileExW", stdcall, dynlib: "kernel32".} proc getEnvironmentStringsW*(): WideCString {. stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".} @@ -369,6 +380,9 @@ else: proc moveFileA*(lpExistingFileName, lpNewFileName: cstring): WINBOOL {. importc: "MoveFileA", stdcall, dynlib: "kernel32".} + proc moveFileExA*(lpExistingFileName, lpNewFileName: WideCString, + flags: DWORD): WINBOOL {. + importc: "MoveFileExA", stdcall, dynlib: "kernel32".} proc getEnvironmentStringsA*(): cstring {. stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".} diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 5521476d9..ff18fc2c2 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -26,7 +26,7 @@ when useWinVersion: from winlean import SocketHandle else: const - versions = "(|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8)" + versions = "(|.38|.39|.41|.43|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8)" when defined(macosx): const DLLSSLName = "libssl" & versions & ".dylib" |