Merge branch 'devel' into araq
This commit is contained in:
commit
2b862b74e0
165 changed files with 4572 additions and 920 deletions
|
|
@ -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, "$"
|
||||
|
||||
|
|
|
|||
|
|
@ -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>".}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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
|
||||
## ==================
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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, "\\\\")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
157
lib/system.nim
157
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.
|
||||
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_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_enable*() {.rtl, inl, benign.}
|
||||
## enables the GC again.
|
||||
|
||||
proc GC_getStatistics*(): string {.rtl, benign.}
|
||||
## returns an informative string about the GC's activity. This may be useful
|
||||
## for tweaking.
|
||||
proc GC_fullCollect*() {.rtl, benign.}
|
||||
## forces a full garbage collection pass.
|
||||
## Ordinary code does not need to call this (and should not).
|
||||
|
||||
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_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_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`.
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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) =
|
||||
|
|
|
|||
|
|
@ -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) =
|
||||
|
|
|
|||
|
|
@ -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.} =
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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, "\'"
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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".}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue