diff options
Diffstat (limited to 'lib')
35 files changed, 695 insertions, 376 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 872d4848d..eda793620 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -601,7 +601,7 @@ proc last*(node: NimNode): NimNode {.compileTime.} = node[<node.len] const - RoutineNodes* = {nnkProcDef, nnkMethodDef, nnkDo, nnkLambda, nnkIteratorDef} + RoutineNodes* = {nnkProcDef, nnkMethodDef, nnkDo, nnkLambda, nnkIteratorDef, nnkTemplateDef, nnkConverterDef} AtomicNodes* = {nnkNone..nnkNilLit} CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, nnkCallStrLit, nnkHiddenCallConv} diff --git a/lib/deprecated/pure/actors.nim b/lib/deprecated/pure/actors.nim index f0791f954..36bd41e9e 100644 --- a/lib/deprecated/pure/actors.nim +++ b/lib/deprecated/pure/actors.nim @@ -40,7 +40,7 @@ type Actor[In, Out] = object{.pure, final.} i: Channel[Task[In, Out]] - t: TThread[ptr Actor[In, Out]] + t: Thread[ptr Actor[In, Out]] PActor*[In, Out] = ptr Actor[In, Out] ## an actor {.deprecated: [TTask: Task, TActor: Actor].} diff --git a/lib/deprecated/pure/sockets.nim b/lib/deprecated/pure/sockets.nim index 5d6fa0078..f7d0950d8 100644 --- a/lib/deprecated/pure/sockets.nim +++ b/lib/deprecated/pure/sockets.nim @@ -39,7 +39,6 @@ when hostOS == "solaris": import os, parseutils from times import epochTime -import unsigned when defined(ssl): import openssl diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 973f1f2ee..10700b59b 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -10,7 +10,6 @@ from pcre import nil import nre.private.util import tables -import unsigned from strutils import toLower, `%` from math import ceil import options diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index b373859f4..469bb69c5 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -55,7 +55,7 @@ when defined(Windows): event*: KEY_EVENT_RECORD safetyBuffer: array[0..5, DWORD] - proc readConsoleInputW*(hConsoleInput: THANDLE, lpBuffer: var INPUTRECORD, + proc readConsoleInputW*(hConsoleInput: HANDLE, lpBuffer: var INPUTRECORD, nLength: uint32, lpNumberOfEventsRead: var uint32): WINBOOL{. stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".} @@ -100,7 +100,7 @@ when defined(Windows): stdout.write "\n" else: - import linenoise, termios, unsigned + import linenoise, termios proc readLineFromStdin*(prompt: string): TaintedString {. tags: [ReadIOEffect, WriteIOEffect].} = diff --git a/lib/nimbase.h b/lib/nimbase.h index bba5ac023..374c0ceb1 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -23,6 +23,30 @@ __clang__ #ifndef NIMBASE_H #define NIMBASE_H +/* ------------ ignore typical warnings in Nim-generated files ------------- */ +#if defined(__GNUC__) || defined(__clang__) +# pragma GCC diagnostic ignored "-Wwritable-strings" +# pragma GCC diagnostic ignored "-Winvalid-noreturn" +# pragma GCC diagnostic ignored "-Wformat" +# pragma GCC diagnostic ignored "-Wlogical-not-parentheses" +# pragma GCC diagnostic ignored "-Wlogical-op-parentheses" +# pragma GCC diagnostic ignored "-Wshadow" +# pragma GCC diagnostic ignored "-Wunused-function" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Winvalid-offsetof" +# pragma GCC diagnostic ignored "-Wtautological-compare" +# pragma GCC diagnostic ignored "-Wswitch-bool" +# pragma GCC diagnostic ignored "-Wmacro-redefined" +# pragma GCC diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers" +#endif + +#if defined(_MSC_VER) +# pragma warning(disable: 4005 4100 4101 4189 4191 4200 4244 4293 4296 4309) +# pragma warning(disable: 4310 4365 4456 4477 4514 4574 4611 4668 4702 4706) +# pragma warning(disable: 4710 4711 4774 4800 4820 4996) +#endif +/* ------------------------------------------------------------------------- */ + #if defined(__GNUC__) # define _GNU_SOURCE 1 #endif diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 2fbde632e..e1d5f902e 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1518,7 +1518,7 @@ proc dirInclude(p: var RstParser): PRstNode = # InternalError("Too many binary zeros in include file") result = parseDoc(q) -proc dirCodeBlock(p: var RstParser, nimrodExtension = false): PRstNode = +proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode = ## Parses a code block. ## ## Code blocks are rnDirective trees with a `kind` of rnCodeBlock. See the @@ -1526,8 +1526,8 @@ proc dirCodeBlock(p: var RstParser, nimrodExtension = false): PRstNode = ## ## Code blocks can come in two forms, the standard `code directive ## <http://docutils.sourceforge.net/docs/ref/rst/directives.html#code>`_ and - ## the nimrod extension ``.. code-block::``. If the block is an extension, we - ## want the default language syntax highlighting to be Nimrod, so we create a + ## the nim extension ``.. code-block::``. If the block is an extension, we + ## want the default language syntax highlighting to be Nim, so we create a ## fake internal field to comminicate with the generator. The field is named ## ``default-language``, which is unlikely to collide with a field specified ## by any random rst input file. @@ -1545,16 +1545,16 @@ proc dirCodeBlock(p: var RstParser, nimrodExtension = false): PRstNode = result.sons[2] = n # Extend the field block if we are using our custom extension. - if nimrodExtension: + if nimExtension: # Create a field block if the input block didn't have any. if result.sons[1].isNil: result.sons[1] = newRstNode(rnFieldList) assert result.sons[1].kind == rnFieldList - # Hook the extra field and specify the Nimrod language as value. + # Hook the extra field and specify the Nim language as value. var extraNode = newRstNode(rnField) extraNode.add(newRstNode(rnFieldName)) extraNode.add(newRstNode(rnFieldBody)) extraNode.sons[0].add(newRstNode(rnLeaf, "default-language")) - extraNode.sons[1].add(newRstNode(rnLeaf, "Nimrod")) + extraNode.sons[1].add(newRstNode(rnLeaf, "Nim")) result.sons[1].add(extraNode) result.kind = rnCodeBlock @@ -1641,7 +1641,7 @@ proc parseDotDot(p: var RstParser): PRstNode = else: rstMessage(p, meInvalidDirective, d) of dkCode: result = dirCodeBlock(p) - of dkCodeBlock: result = dirCodeBlock(p, nimrodExtension = true) + of dkCodeBlock: result = dirCodeBlock(p, nimExtension = true) of dkIndex: result = dirIndex(p) else: rstMessage(p, meInvalidDirective, d) popInd(p) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 22d944597..8b5bb0e8f 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -757,10 +757,15 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) = template valid(s): expr = s.len > 0 and allCharsInSet(s, {'.','/',':','%','_','\\','\128'..'\xFF'} + Digits + Letters + WhiteSpace) - - var options = "" + let + arg = getArgument(n) + isObject = arg.toLower().endsWith(".svg") + var + options = "" + content = "" var s = getFieldValue(n, "scale") - if s.valid: dispA(d.target, options, " scale=\"$1\"", " scale=$1", [strip(s)]) + if s.valid: dispA(d.target, options, if isObject: "" else: " scale=\"$1\"", + " scale=$1", [strip(s)]) s = getFieldValue(n, "height") if s.valid: dispA(d.target, options, " height=\"$1\"", " height=$1", [strip(s)]) @@ -769,16 +774,21 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) = if s.valid: dispA(d.target, options, " width=\"$1\"", " width=$1", [strip(s)]) s = getFieldValue(n, "alt") - if s.valid: dispA(d.target, options, " alt=\"$1\"", "", [strip(s)]) + if s.valid: + # <object> displays its content if it cannot render the image + if isObject: dispA(d.target, content, "$1", "", [strip(s)]) + else: dispA(d.target, options, " alt=\"$1\"", "", [strip(s)]) s = getFieldValue(n, "align") if s.valid: dispA(d.target, options, " align=\"$1\"", "", [strip(s)]) if options.len > 0: options = dispF(d.target, "$1", "[$1]", [options]) - - let arg = getArgument(n) + if arg.valid: - dispA(d.target, result, "<img src=\"$1\"$2 />", "\\includegraphics$2{$1}", + let htmlOut = if isObject: + "<object data=\"$1\" type=\"image/svg+xml\"$2 >" & content & "</object>" + else: "<img src=\"$1\"$2 />" + dispA(d.target, result, htmlOut, "\\includegraphics$2{$1}", [arg, options]) if len(n) >= 3: renderRstToOut(d, n.sons[2], result) @@ -802,7 +812,7 @@ proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) = if parseInt(n.getFieldValue, number) > 0: params.startLine = number of "file": - # The ``file`` option is a Nimrod extension to the official spec, it acts + # The ``file`` option is a Nim extension to the official spec, it acts # like it would for other directives like ``raw`` or ``cvs-table``. This # field is dealt with in ``rst.nim`` which replaces the existing block with # the referenced file, so we only need to ignore it here to avoid incorrect @@ -871,7 +881,7 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) = ## second the code block itself. The code block can use syntax highlighting, ## which depends on the directive argument specified by the rst input, and ## may also come from the parser through the internal ``default-language`` - ## option to differentiate between a plain code block and nimrod's code block + ## option to differentiate between a plain code block and Nim's code block ## extension. assert n.kind == rnCodeBlock if n.sons[2] == nil: return diff --git a/lib/phpcl.nim b/lib/phpcl.nim new file mode 100644 index 000000000..5eaa00f80 --- /dev/null +++ b/lib/phpcl.nim @@ -0,0 +1,50 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## PHP compatibility layer. + +type + PhpArray*[Key, Val] = ref object + + PhpObj* = ref object ## can be a string, an int etc. + +proc explode*(sep, x: string): seq[string] {.importc: "explode".} +template split*(x, sep: string): seq[string] = explode(sep, x) + +proc `$`*(x: PhpObj): string {.importcpp: "(#)".} +proc `++`*(x: PhpObj) {.importcpp: "++(#)".} + +proc `==`*(x, y: PhpObj): string {.importcpp: "((#) == (#))".} +proc `<=`*(x, y: PhpObj): string {.importcpp: "((#) <= (#))".} +proc `<`*(x, y: PhpObj): string {.importcpp: "((#) < (#))".} + +proc toUpper*(x: string): string {.importc: "strtoupper".} +proc toLower*(x: string): string {.importc: "strtolower".} + +proc strtr*(s: string, replacePairs: PhpArray[string, string]): string {.importc.} +proc strtr*(s, fromm, to: string): string {.importc.} + +proc toArray*[K,V](pairs: openarray[(K,V)]): PhpArray[K,V] {.magic: + "Array".} +template strtr*(s: string, replacePairs: openarray[(string, string)]): string = + strtr(toArray(replacePairs)) + +iterator pairs*[K,V](d: PhpArray[K,V]): (K,V) = + var k: K + var v: V + {.emit: "foreach (`d` as `k`=>`v`) {".} + yield (k, v) + {.emit: "}".} + +proc `[]`*[K,V](d: PhpArray[K,V]; k: K): V {.importcpp: "#[#]".} +proc `[]=`*[K,V](d: PhpArray[K,V]; k: K; v: V) {.importcpp: "#[#] = #".} + +proc ksort*[K,V](d: PhpArray[K,V]) {.importc.} +proc krsort*[K,V](d: PhpArray[K,V]) {.importc.} +proc keys*[K,V](d: PhpArray[K,V]): seq[K] {.importc.} diff --git a/lib/pure/collections/LockFreeHash.nim b/lib/pure/collections/LockFreeHash.nim index 1d4471b21..a3ead81e3 100644 --- a/lib/pure/collections/LockFreeHash.nim +++ b/lib/pure/collections/LockFreeHash.nim @@ -1,6 +1,6 @@ #nim c -t:-march=i686 --cpu:amd64 --threads:on -d:release lockfreehash.nim -import unsigned, math, hashes +import math, hashes #------------------------------------------------------------------------------ ## Memory Utility Functions diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index abe9cf85e..9a42a21ee 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -951,7 +951,7 @@ when isMainModule and not defined(release): var b = initOrderedSet[int]() for x in [2, 4, 5]: b.incl(x) assert($a == $b) - assert(a == b) # https://github.com/Araq/Nimrod/issues/1413 + assert(a == b) # https://github.com/Araq/Nim/issues/1413 block initBlocks: var a: OrderedSet[int] diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index 7328f7c24..f4c027576 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -6,7 +6,7 @@ # distribution, for details about the copyright. # -## This module implements color handling for Nimrod. It is used by +## This module implements color handling for Nim. It is used by ## the ``graphics`` module. import strutils diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 2603835dd..a30d49889 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -328,10 +328,10 @@ proc distinguishedSlave(w: ptr Worker) {.thread.} = if w.q.len != 0: w.cleanFlowVars var - workers: array[MaxThreadPoolSize, TThread[ptr Worker]] + workers: array[MaxThreadPoolSize, Thread[ptr Worker]] workersData: array[MaxThreadPoolSize, Worker] - distinguished: array[MaxDistinguishedThread, TThread[ptr Worker]] + distinguished: array[MaxDistinguishedThread, Thread[ptr Worker]] distinguishedData: array[MaxDistinguishedThread, Worker] when defined(nimPinToCpu): @@ -468,7 +468,7 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} = await(gSomeReady) var - distinguishedLock: TLock + distinguishedLock: Lock initLock distinguishedLock diff --git a/lib/pure/future.nim b/lib/pure/future.nim index 4767266e5..3793edc8b 100644 --- a/lib/pure/future.nim +++ b/lib/pure/future.nim @@ -134,7 +134,7 @@ macro `[]`*(lc: ListComprehension, comp, typ: expr): expr = ## comprehension, for example ``x | (x <- 1..10, x mod 2 == 0)``. `typ` is ## the type that will be stored inside the result seq. ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## echo lc[x | (x <- 1..10, x mod 2 == 0), int] ## diff --git a/lib/pure/json.nim b/lib/pure/json.nim index ab7d18bd8..f672a0c1b 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -712,17 +712,21 @@ proc `%`*(elements: openArray[JsonNode]): JsonNode = proc toJson(x: NimNode): NimNode {.compiletime.} = case x.kind - of nnkBracket: + of nnkBracket: # array result = newNimNode(nnkBracket) for i in 0 .. <x.len: result.add(toJson(x[i])) - of nnkTableConstr: + of nnkTableConstr: # object result = newNimNode(nnkTableConstr) for i in 0 .. <x.len: - assert x[i].kind == nnkExprColonExpr + x[i].expectKind nnkExprColonExpr result.add(newNimNode(nnkExprColonExpr).add(x[i][0]).add(toJson(x[i][1]))) + of nnkCurly: # empty object + result = newNimNode(nnkTableConstr) + x.expectLen(0) + else: result = x diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim index c8090dc6a..ae0845714 100644 --- a/lib/pure/mersenne.nim +++ b/lib/pure/mersenne.nim @@ -1,5 +1,3 @@ -import unsigned - type MersenneTwister* = object mt: array[0..623, uint32] diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index b5a8d5777..3951b46a3 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -12,7 +12,7 @@ # TODO: Clean up the exports a bit and everything else in general. -import unsigned, os +import os when hostOS == "solaris": {.passl: "-lsocket -lnsl".} diff --git a/lib/pure/net.nim b/lib/pure/net.nim index d1016011e..346b656a0 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -10,7 +10,7 @@ ## This module implements a high-level cross-platform sockets interface. {.deadCodeElim: on.} -import nativesockets, os, strutils, unsigned, parseutils, times +import nativesockets, os, strutils, parseutils, times export Port, `$`, `==` const useWinVersion = defined(Windows) or defined(nimdoc) @@ -102,8 +102,7 @@ type ## case of IPv4 {.deprecated: [TIpAddress: IpAddress].} -proc isIpAddress*(address_str: string): bool {.tags: [].} -proc parseIpAddress*(address_str: string): IpAddress + proc socketError*(socket: Socket, err: int = -1, async = false, lastError = (-1).OSErrorCode): void @@ -548,40 +547,6 @@ proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) { var valuei = cint(if value: 1 else: 0) setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei) -proc connect*(socket: Socket, address: string, - port = Port(0)) {.tags: [ReadIOEffect].} = - ## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a - ## host name. If ``address`` is a host name, this function will try each IP - ## of that host name. ``htons`` is already performed on ``port`` so you must - ## not do it. - ## - ## If ``socket`` is an SSL socket a handshake will be automatically performed. - var aiList = getAddrInfo(address, port, socket.domain) - # try all possibilities: - var success = false - var lastError: OSErrorCode - var it = aiList - while it != nil: - if connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32: - success = true - break - else: lastError = osLastError() - it = it.ai_next - - dealloc(aiList) - if not success: raiseOSError(lastError) - - when defined(ssl): - if socket.isSSL: - # RFC3546 for SNI specifies that IP addresses are not allowed. - if not isIpAddress(address): - # Discard result in case OpenSSL version doesn't support SNI, or we're - # not using TLSv1+ - discard SSL_set_tlsext_host_name(socket.sslHandle, address) - - let ret = SSLConnect(socket.sslHandle) - socketError(socket, ret) - when defined(ssl): proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} = ## This proc needs to be called on a socket after it connects. This is @@ -829,7 +794,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1, template addNLIfEmpty(): stmt = if line.len == 0: - line.add("\c\L") + line.string.add("\c\L") template raiseSockError(): stmt {.dirty, immediate.} = let lastError = getSocketError(socket) @@ -971,61 +936,6 @@ proc sendTo*(socket: Socket, address: string, port: Port, ## This is the high-level version of the above ``sendTo`` function. result = socket.sendTo(address, port, cstring(data), data.len) -proc connectAsync(socket: Socket, name: string, port = Port(0), - af: Domain = AF_INET) {.tags: [ReadIOEffect].} = - ## A variant of ``connect`` for non-blocking sockets. - ## - ## This procedure will immediately return, it will not block until a connection - ## is made. It is up to the caller to make sure the connection has been established - ## by checking (using ``select``) whether the socket is writeable. - ## - ## **Note**: For SSL sockets, the ``handshake`` procedure must be called - ## whenever the socket successfully connects to a server. - var aiList = getAddrInfo(name, port, af) - # try all possibilities: - var success = false - var lastError: OSErrorCode - var it = aiList - while it != nil: - var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) - if ret == 0'i32: - success = true - break - else: - lastError = osLastError() - when useWinVersion: - # Windows EINTR doesn't behave same as POSIX. - if lastError.int32 == WSAEWOULDBLOCK: - success = true - break - else: - if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS: - success = true - break - - it = it.ai_next - - dealloc(aiList) - if not success: raiseOSError(lastError) - -proc connect*(socket: Socket, address: string, port = Port(0), - timeout: int) {.tags: [ReadIOEffect, WriteIOEffect].} = - ## Connects to server as specified by ``address`` on port specified by ``port``. - ## - ## The ``timeout`` paremeter specifies the time in milliseconds to allow for - ## the connection to the server to be made. - socket.fd.setBlocking(false) - - socket.connectAsync(address, port, socket.domain) - var s = @[socket.fd] - if selectWrite(s, timeout) != 1: - raise newException(TimeoutError, "Call to 'connect' timed out.") - else: - when defined(ssl): - if socket.isSSL: - socket.fd.setBlocking(true) - doAssert socket.handshake() - socket.fd.setBlocking(true) proc isSsl*(socket: Socket): bool = ## Determines whether ``socket`` is a SSL socket. @@ -1295,7 +1205,8 @@ proc parseIPv6Address(address_str: string): IpAddress = raise newException(ValueError, "Invalid IP Address. The address consists of too many groups") -proc parseIpAddress(address_str: string): IpAddress = + +proc parseIpAddress*(address_str: string): IpAddress = ## Parses an IP address ## Raises EInvalidValue on error if address_str == nil: @@ -1305,8 +1216,7 @@ proc parseIpAddress(address_str: string): IpAddress = else: return parseIPv4Address(address_str) - -proc isIpAddress(address_str: string): bool = +proc isIpAddress*(address_str: string): bool {.tags: [].} = ## Checks if a string is an IP address ## Returns true if it is, false otherwise try: @@ -1314,3 +1224,94 @@ proc isIpAddress(address_str: string): bool = except ValueError: return false return true + + +proc connect*(socket: Socket, address: string, + port = Port(0)) {.tags: [ReadIOEffect].} = + ## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a + ## host name. If ``address`` is a host name, this function will try each IP + ## of that host name. ``htons`` is already performed on ``port`` so you must + ## not do it. + ## + ## If ``socket`` is an SSL socket a handshake will be automatically performed. + var aiList = getAddrInfo(address, port, socket.domain) + # try all possibilities: + var success = false + var lastError: OSErrorCode + var it = aiList + while it != nil: + if connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32: + success = true + break + else: lastError = osLastError() + it = it.ai_next + + dealloc(aiList) + if not success: raiseOSError(lastError) + + when defined(ssl): + if socket.isSSL: + # RFC3546 for SNI specifies that IP addresses are not allowed. + if not isIpAddress(address): + # Discard result in case OpenSSL version doesn't support SNI, or we're + # not using TLSv1+ + discard SSL_set_tlsext_host_name(socket.sslHandle, address) + + let ret = SSLConnect(socket.sslHandle) + socketError(socket, ret) + +proc connectAsync(socket: Socket, name: string, port = Port(0), + af: Domain = AF_INET) {.tags: [ReadIOEffect].} = + ## A variant of ``connect`` for non-blocking sockets. + ## + ## This procedure will immediately return, it will not block until a connection + ## is made. It is up to the caller to make sure the connection has been established + ## by checking (using ``select``) whether the socket is writeable. + ## + ## **Note**: For SSL sockets, the ``handshake`` procedure must be called + ## whenever the socket successfully connects to a server. + var aiList = getAddrInfo(name, port, af) + # try all possibilities: + var success = false + var lastError: OSErrorCode + var it = aiList + while it != nil: + var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) + if ret == 0'i32: + success = true + break + else: + lastError = osLastError() + when useWinVersion: + # Windows EINTR doesn't behave same as POSIX. + if lastError.int32 == WSAEWOULDBLOCK: + success = true + break + else: + if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS: + success = true + break + + it = it.ai_next + + dealloc(aiList) + if not success: raiseOSError(lastError) + +proc connect*(socket: Socket, address: string, port = Port(0), + timeout: int) {.tags: [ReadIOEffect, WriteIOEffect].} = + ## Connects to server as specified by ``address`` on port specified by ``port``. + ## + ## The ``timeout`` paremeter specifies the time in milliseconds to allow for + ## the connection to the server to be made. + socket.fd.setBlocking(false) + + socket.connectAsync(address, port, socket.domain) + var s = @[socket.fd] + if selectWrite(s, timeout) != 1: + raise newException(TimeoutError, "Call to 'connect' timed out.") + else: + when defined(ssl): + if socket.isSSL: + socket.fd.setBlocking(true) + doAssert socket.handshake() + socket.fd.setBlocking(true) diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim index e2397b91c..5a7deaab0 100644 --- a/lib/pure/nimprof.nim +++ b/lib/pure/nimprof.nim @@ -12,7 +12,7 @@ ## report at program exit. when not defined(profiler) and not defined(memProfiler): - {.warning: "Profiling support is turned off!".} + {.error: "Profiling support is turned off! Enable profiling by passing `--profiler:on --stackTrace:on` to the compiler (see the Nim Compiler User Guide for more options).".} # We don't want to profile the profiling code ... {.push profiler: off.} diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 1e00f92b1..a92b74484 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -774,6 +774,7 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} = res: int res = findFirstFile(pattern, f) if res != -1: + defer: findClose(res) while true: if not skipFindData(f) and (f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) == 0'i32: @@ -786,7 +787,6 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} = pattern[dotPos+1] == '*': yield splitFile(pattern).dir / extractFilename(ff) if findNextFile(res, f) == 0'i32: break - findClose(res) else: # here we use glob var f: Glob @@ -795,11 +795,11 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} = f.gl_pathc = 0 f.gl_pathv = nil res = glob(pattern, 0, nil, addr(f)) + defer: globfree(addr(f)) if res == 0: for i in 0.. f.gl_pathc - 1: assert(f.gl_pathv[i] != nil) yield $f.gl_pathv[i] - globfree(addr(f)) type PathComponent* = enum ## Enumeration specifying a path component. @@ -845,6 +845,7 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: var f: WIN32_FIND_DATA var h = findFirstFile(dir / "*", f) if h != -1: + defer: findClose(h) while true: var k = pcFile if not skipFindData(f): @@ -856,10 +857,10 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: else: dir / extractFilename(getFilename(f)) yield (k, xx) if findNextFile(h, f) == 0'i32: break - findClose(h) else: var d = opendir(dir) if d != nil: + defer: discard closedir(d) while true: var x = readdir(d) if x == nil: break @@ -883,7 +884,6 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: if S_ISDIR(s.st_mode): k = pcDir if S_ISLNK(s.st_mode): k = succ(k) yield (k, y) - discard closedir(d) iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {. tags: [ReadDirEffect].} = diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index e9f5bee0a..9fc816f2f 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -567,7 +567,9 @@ when declared(getEnv) or defined(nimscript): var path = string(getEnv("PATH")) for candidate in split(path, PathSep): when defined(windows): - var x = candidate / result + var x = (if candidate[0] == '"' and candidate[^1] == '"': + substr(candidate, 1, candidate.len-2) else: candidate) / + result else: var x = expandTilde(candidate) / result if existsFile(x): return x diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 8560c3ee4..38b0ed4a3 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -876,7 +876,7 @@ elif not defined(useNimRtl): let sizeRead = read(data.pErrorPipe[readIdx], addr error, sizeof(error)) if sizeRead == sizeof(error): raiseOSError("Could not find command: '$1'. OS error: $2" % - [$data.sysCommand, $strerror(error)]) + [$data.sysCommand, $strerror(error)]) return pid @@ -886,7 +886,7 @@ elif not defined(useNimRtl): discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error)) exitnow(1) - when defined(macosx) or defined(freebsd) or defined(netbsd) or defined(android): + when not defined(uClibc) and (not defined(linux) or defined(android)): var environ {.importc.}: cstringArray proc startProcessAfterFork(data: ptr StartProcessData) = @@ -916,17 +916,16 @@ elif not defined(useNimRtl): discard fcntl(data.pErrorPipe[writeIdx], F_SETFD, FD_CLOEXEC) if data.optionPoUsePath: - when defined(macosx) or defined(freebsd) or defined(netbsd) or defined(android): + when defined(uClibc): + # uClibc environment (OpenWrt included) doesn't have the full execvpe + discard execve(data.sysCommand, data.sysArgs, data.sysEnv) + elif defined(linux) and not defined(android): + discard execvpe(data.sysCommand, data.sysArgs, data.sysEnv) + else: # MacOSX doesn't have execvpe, so we need workaround. # On MacOSX we can arrive here only from fork, so this is safe: environ = data.sysEnv discard execvp(data.sysCommand, data.sysArgs) - else: - when defined(uClibc): - # uClibc environment (OpenWrt included) doesn't have the full execvpe - discard execve(data.sysCommand, data.sysArgs, data.sysEnv) - else: - discard execvpe(data.sysCommand, data.sysArgs, data.sysEnv) else: discard execve(data.sysCommand, data.sysArgs, data.sysEnv) diff --git a/lib/pure/securehash.nim b/lib/pure/securehash.nim index 8ac6acb0e..657782889 100644 --- a/lib/pure/securehash.nim +++ b/lib/pure/securehash.nim @@ -7,8 +7,7 @@ # distribution, for details about the copyright. # -import - strutils, unsigned +import strutils const Sha1DigestSize = 20 diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index 832f5f4f9..89e92c133 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -9,7 +9,7 @@ # TODO: Docs. -import os, unsigned, hashes +import os, hashes when defined(linux): import posix, epoll @@ -118,7 +118,7 @@ elif defined(linux): # are therefore constantly ready. (leading to 100% CPU usage). if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0: raiseOSError(osLastError()) - s.fds.mget(fd).events = events + s.fds[fd].events = events else: var event = createEventStruct(events, fd) if s.fds[fd].events == {}: @@ -129,7 +129,7 @@ elif defined(linux): else: if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0: raiseOSError(osLastError()) - s.fds.mget(fd).events = events + s.fds[fd].events = events proc unregister*(s: var Selector, fd: SocketHandle) = if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0: @@ -229,7 +229,7 @@ elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd): modifyKQueue(s.kqFD, fd, event, EV_ADD) for event in previousEvents-events: modifyKQueue(s.kqFD, fd, event, EV_DELETE) - s.fds.mget(fd).events = events + s.fds[fd].events = events proc unregister*(s: var Selector, fd: SocketHandle) = for event in s.fds[fd].events: @@ -298,7 +298,7 @@ elif not defined(nimdoc): proc update*(s: var Selector, fd: SocketHandle, events: set[Event]) = #if not s.fds.hasKey(fd): # raise newException(ValueError, "File descriptor not found.") - s.fds.mget(fd).events = events + s.fds[fd].events = events proc unregister*(s: var Selector, fd: SocketHandle) = s.fds.del(fd) diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 38e91fee4..bb6175a12 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -148,7 +148,10 @@ proc write*[T](s: Stream, x: T) = proc write*(s: Stream, x: string) = ## writes the string `x` to the the stream `s`. No length field or ## terminating zero is written. - writeData(s, cstring(x), x.len) + when nimvm: + writeData(s, cstring(x), x.len) + else: + if x.len > 0: writeData(s, unsafeAddr x[0], x.len) proc writeLn*(s: Stream, args: varargs[string, `$`]) {.deprecated.} = ## **Deprecated since version 0.11.4:** Use **writeLine** instead. diff --git a/lib/system.nim b/lib/system.nim index e884e784c..2c049b6b6 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -151,7 +151,7 @@ proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} = ## echo cast[ptr char](p)[] # b discard -proc unsafeAddr*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} = +proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} = ## Builtin 'addr' operator for taking the address of a memory location. ## This works even for ``let`` variables or parameters for better interop ## with C and so it is considered even more unsafe than the ordinary ``addr``. @@ -1811,7 +1811,7 @@ const NimMinor*: int = 13 ## is the minor number of Nim's version. - NimPatch*: int = 0 + NimPatch*: int = 1 ## is the patch number of Nim's version. NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch @@ -2452,14 +2452,17 @@ type when defined(JS): proc add*(x: var string, y: cstring) {.asmNoStackFrame.} = - asm """ - var len = `x`[0].length-1; - for (var i = 0; i < `y`.length; ++i) { - `x`[0][len] = `y`.charCodeAt(i); - ++len; - } - `x`[0][len] = 0 - """ + when defined(nimphp): + asm """`x` .= `y`;""" + else: + asm """ + var len = `x`[0].length-1; + for (var i = 0; i < `y`.length; ++i) { + `x`[0][len] = `y`.charCodeAt(i); + ++len; + } + `x`[0][len] = 0 + """ proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} elif hasAlloc: @@ -2960,9 +2963,9 @@ when not defined(JS): #and not defined(nimscript): ## buffer.add(line.replace("a", "0") & '\x0A') ## writeFile(filename, buffer) var f = open(filename, bufSize=8000) + defer: close(f) var res = TaintedString(newStringOfCap(80)) while f.readLine(res): yield res - close(f) iterator lines*(f: File): TaintedString {.tags: [ReadIOEffect].} = ## Iterate over any line in the file `f`. diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index b4462ed83..6de8e19e7 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -688,7 +688,7 @@ proc rawDealloc(a: var MemRegion, p: pointer) = sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %% s == 0, "rawDealloc 3") var f = cast[ptr FreeCell](p) - #echo("setting to nil: ", $cast[TAddress](addr(f.zeroField))) + #echo("setting to nil: ", $cast[ByteAddress](addr(f.zeroField))) sysAssert(f.zeroField != 0, "rawDealloc 1") f.zeroField = 0 f.next = c.freeList diff --git a/lib/system/gc.nim b/lib/system/gc.nim index c25cf4606..d8390ca14 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -325,6 +325,8 @@ proc cellsetReset(s: var CellSet) = deinit(s) init(s) +{.push stacktrace:off.} + proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = var d = cast[ByteAddress](dest) case n.kind @@ -459,7 +461,8 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = result = cellToUsr(res) sysAssert(allocInv(gch.region), "rawNewObj end") -{.pop.} +{.pop.} # .stackTrace off +{.pop.} # .profiler off proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} = result = rawNewObj(typ, size, gch) @@ -576,7 +579,7 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = proc growObj(old: pointer, newsize: int): pointer {.rtl.} = result = growObj(old, newsize, gch) -{.push profiler:off.} +{.push profiler:off, stackTrace:off.} # ---------------- cycle collector ------------------------------------------- @@ -659,7 +662,7 @@ when useMarkForDebug or useBackupGc: proc stackMarkS(gch: var GcHeap, p: pointer) {.inline.} = # the addresses are not as cells on the stack, so turn them to cells: var cell = usrToCell(p) - var c = cast[TAddress](cell) + var c = cast[ByteAddress](cell) if c >% PageSize: # fast check: does it look like a cell? var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell)) @@ -805,8 +808,8 @@ proc markThreadStacks(gch: var GcHeap) = while it != nil: # mark registers: for i in 0 .. high(it.registers): gcMark(gch, it.registers[i]) - var sp = cast[TAddress](it.stackBottom) - var max = cast[TAddress](it.stackTop) + var sp = cast[ByteAddress](it.stackBottom) + var max = cast[ByteAddress](it.stackTop) # XXX stack direction? # XXX unroll this loop: while sp <=% max: @@ -1018,4 +1021,4 @@ when not defined(useNimRtl): result = result & "[GC] max stack size: " & $gch.stat.maxStackSize & "\n" GC_enable() -{.pop.} +{.pop.} # profiler: off, stackTrace: off diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim index e68a8586e..6b6b81824 100644 --- a/lib/system/gc2.nim +++ b/lib/system/gc2.nim @@ -104,8 +104,6 @@ when not defined(useNimRtl): proc initGC() = when not defined(useNimRtl): - when traceGC: - for i in low(CellState)..high(CellState): init(states[i]) gch.cycleThreshold = InitialCycleThreshold gch.stat.stackScans = 0 gch.stat.cycleCollections = 0 @@ -168,8 +166,10 @@ proc writeCell(msg: cstring, c: PCell) = c_fprintf(c_stdout, "[GC] %s: %p %d rc=%ld; color=%ld\n", msg, c, kind, c.refcount shr rcShift, c.color) +proc myastToStr[T](x: T): string {.magic: "AstToStr", noSideEffect.} + template gcTrace(cell, state: expr): stmt {.immediate.} = - when traceGC: traceCell(cell, state) + when traceGC: writeCell(myastToStr(state), cell) # forward declarations: proc collectCT(gch: var GcHeap) {.benign.} @@ -568,7 +568,7 @@ template takeTime {.dirty.} = template checkTime {.dirty.} = if debugticker <= 0: - echo "in loop" + #echo "in loop" debugticker = 1000 when withRealTime: if steps == 0: @@ -602,8 +602,9 @@ proc freeCyclicCell(gch: var GcHeap, c: PCell) = proc sweep(gch: var GcHeap): bool = takeStartTime(100) - echo "loop start" + #echo "loop start" let black = gch.black + cfprintf(cstdout, "black is %d\n", black) while true: let x = allObjectsAsProc(gch.region, addr gch.spaceIter) if gch.spaceIter.state < 0: break @@ -619,7 +620,7 @@ proc sweep(gch: var GcHeap): bool = # traversal over the heap! checkTime() # prepare for next iteration: - echo "loop end" + #echo "loop end" gch.spaceIter = ObjectSpaceIter() result = true @@ -634,6 +635,9 @@ proc markIncremental(gch: var GcHeap): bool = takeStartTime(100) while L[] > 0: var c = gch.greyStack.d[0] + if not isAllocatedPtr(gch.region, c): + c_fprintf(c_stdout, "[GC] not allocated anymore: %p\n", c) + sysAssert(isAllocatedPtr(gch.region, c), "markIncremental: isAllocatedPtr") gch.greyStack.d[0] = gch.greyStack.d[L[] - 1] dec(L[]) diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index 47e8b4b1f..013dc55f8 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -78,19 +78,29 @@ iterator items(stack: ptr GcStack): ptr GcStack = yield s s = s.next -var - localGcInitialized {.rtlThreadVar.}: bool +# There will be problems with GC in foreign threads if `threads` option is off or TLS emulation is enabled +const allowForeignThreadGc = compileOption("threads") and not compileOption("tlsEmulation") -proc setupForeignThreadGc*() = - ## call this if you registered a callback that will be run from a thread not - ## under your control. This has a cheap thread-local guard, so the GC for - ## this thread will only be initialized once per thread, no matter how often - ## it is called. - if not localGcInitialized: - localGcInitialized = true - var stackTop {.volatile.}: pointer - setStackBottom(addr(stackTop)) - initGC() +when allowForeignThreadGc: + var + localGcInitialized {.rtlThreadVar.}: bool + + proc setupForeignThreadGc*() = + ## Call this if you registered a callback that will be run from a thread not + ## under your control. This has a cheap thread-local guard, so the GC for + ## this thread will only be initialized once per thread, no matter how often + ## it is called. + ## + ## This function is availble only when ``--threads:on`` and ``--tlsEmulation:off`` + ## switches are used + if not localGcInitialized: + localGcInitialized = true + var stackTop {.volatile.}: pointer + setStackBottom(addr(stackTop)) + initGC() +else: + template setupForeignThreadGc*(): stmt = + {.error: "setupForeignThreadGc is availble only when ``--threads:on`` and ``--tlsEmulation:off`` are used".} # ----------------- stack management -------------------------------------- # inspired from Smart Eiffel @@ -131,9 +141,9 @@ when defined(sparc): # For SPARC architecture. proc isOnStack(p: pointer): bool = var stackTop {.volatile.}: pointer stackTop = addr(stackTop) - var b = cast[TAddress](gch.stackBottom) - var a = cast[TAddress](stackTop) - var x = cast[TAddress](p) + var b = cast[ByteAddress](gch.stackBottom) + var a = cast[ByteAddress](stackTop) + var x = cast[ByteAddress](p) result = a <=% x and x <=% b template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} = @@ -150,7 +160,7 @@ when defined(sparc): # For SPARC architecture. # Addresses decrease as the stack grows. while sp <= max: gcMark(gch, sp[]) - sp = cast[PPointer](cast[TAddress](sp) +% sizeof(pointer)) + sp = cast[PPointer](cast[ByteAddress](sp) +% sizeof(pointer)) elif defined(ELATE): {.error: "stack marking code is to be written for this architecture".} diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 5bac54772..ceeb5563f 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -1,7 +1,7 @@ # # # Nim's Runtime Library -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -61,7 +61,6 @@ proc getCurrentExceptionMsg*(): string = proc auxWriteStackTrace(f: PCallFrame): string = type TempFrame = tuple[procname: cstring, line: int] - {.deprecated: [TTempFrame: TempFrame].} var it = f i = 0 @@ -128,8 +127,11 @@ proc reraiseException() {.compilerproc, asmNoStackFrame.} = else: when not defined(noUnhandledHandler): if excHandler == 0: - var isNimException : bool - asm "`isNimException` = lastJSError.m_type;" + var isNimException: bool + when defined(nimphp): + asm "`isNimException` = isset(`lastJSError`['m_type']);" + else: + asm "`isNimException` = lastJSError.m_type;" if isNimException: unhandledException(cast[ref Exception](lastJSError)) asm "throw lastJSError;" @@ -150,33 +152,89 @@ proc raiseFieldError(f: string) {.compilerproc, noreturn.} = raise newException(FieldError, f & " is not accessible") proc SetConstr() {.varargs, asmNoStackFrame, compilerproc.} = - asm """ - var result = {}; - for (var i = 0; i < arguments.length; ++i) { - var x = arguments[i]; - if (typeof(x) == "object") { - for (var j = x[0]; j <= x[1]; ++j) { - result[j] = true; + when defined(nimphp): + asm """ + $args = func_get_args(); + $result = array(); + foreach ($args as $x) { + if (is_array($x)) { + for ($j = $x[0]; $j <= $x[1]; $j++) { + $result[$j] = true; + } + } else { + $result[$x] = true; + } + } + return $result; + """ + else: + asm """ + var result = {}; + for (var i = 0; i < arguments.length; ++i) { + var x = arguments[i]; + if (typeof(x) == "object") { + for (var j = x[0]; j <= x[1]; ++j) { + result[j] = true; + } + } else { + result[x] = true; } - } else { - result[x] = true; } + return result; + """ + +proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} = + when defined(nimphp): + {.emit: """return `c`;""".} + else: + {.emit: """ + var ln = `c`.length; + var result = new Array(ln + 1); + var i = 0; + for (; i < ln; ++i) { + result[i] = `c`.charCodeAt(i); } + result[i] = 0; // terminating zero return result; - """ + """.} proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} = - asm """ - var result = []; - for (var i = 0; i < `c`.length; ++i) { - result[i] = `c`.charCodeAt(i); + when defined(nimphp): + {.emit: """return `c`;""".} + else: + {.emit: """ + var ln = `c`.length; + var result = new Array(ln); + var r = 0; + for (var i = 0; i < ln; ++i) { + var ch = `c`.charCodeAt(i); + + if (ch < 128) { + result[r] = ch; } - result[result.length] = 0; // terminating zero - return result; - """ + else if((ch > 127) && (ch < 2048)) { + result[r] = (ch >> 6) | 192; + ++r; + result[r] = (ch & 63) | 128; + } + else { + result[r] = (ch >> 12) | 224; + ++r; + result[r] = ((ch >> 6) & 63) | 128; + ++r; + result[r] = (ch & 63) | 128; + } + ++r; + } + result[r] = 0; // terminating zero + return result; + """.} proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} = - asm """ + when defined(nimphp): + {.emit: """return `s`;""".} + else: + asm """ var len = `s`.length-1; var asciiPart = new Array(len); var fcc = String.fromCharCode; @@ -203,62 +261,118 @@ proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} = """ proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} = - asm """ - var result = new Array(`len`+1); - result[0] = 0; - result[`len`] = 0; - return result; - """ + when defined(nimphp): + asm """ + $result = array(); + for($i = 0; $i < `len`; $i++) $result[] = chr(0); + return $result; + """ + else: + asm """ + var result = new Array(`len`+1); + result[0] = 0; + result[`len`] = 0; + return result; + """ + +when defined(nimphp): + proc nimSubstr(s: string; a, b: int): string {. + asmNoStackFrame, compilerproc.} = + asm """return substr(`s`,`a`,`b`-`a`+1);""" proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} = # argument type is a fake - asm """ - var result = 0; - for (var elem in `a`) { ++result; } - return result; - """ + when defined(nimphp): + asm """ + return count(`a`); + """ + else: + asm """ + var result = 0; + for (var elem in `a`) { ++result; } + return result; + """ proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} = - asm """ - for (var elem in `a`) { if (!`b`[elem]) return false; } - for (var elem in `b`) { if (!`a`[elem]) return false; } - return true; - """ + when defined(nimphp): + asm """ + foreach (`a` as $elem=>$_) { if (!isset(`b`[$elem])) return false; } + foreach (`b` as $elem=>$_) { if (!isset(`a`[$elem])) return false; } + return true; + """ + else: + asm """ + for (var elem in `a`) { if (!`b`[elem]) return false; } + for (var elem in `b`) { if (!`a`[elem]) return false; } + return true; + """ proc SetLe(a, b: int): bool {.compilerproc, asmNoStackFrame.} = - asm """ - for (var elem in `a`) { if (!`b`[elem]) return false; } - return true; - """ + when defined(nimphp): + asm """ + foreach (`a` as $elem=>$_) { if (!isset(`b`[$elem])) return false; } + return true; + """ + else: + asm """ + for (var elem in `a`) { if (!`b`[elem]) return false; } + return true; + """ proc SetLt(a, b: int): bool {.compilerproc.} = result = SetLe(a, b) and not SetEq(a, b) proc SetMul(a, b: int): int {.compilerproc, asmNoStackFrame.} = - asm """ - var result = {}; - for (var elem in `a`) { - if (`b`[elem]) { result[elem] = true; } - } - return result; - """ + when defined(nimphp): + asm """ + var $result = array(); + foreach (`a` as $elem=>$_) { + if (isset(`b`[$elem])) { $result[$elem] = true; } + } + return $result; + """ + else: + asm """ + var result = {}; + for (var elem in `a`) { + if (`b`[elem]) { result[elem] = true; } + } + return result; + """ proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} = - asm """ - var result = {}; - for (var elem in `a`) { result[elem] = true; } - for (var elem in `b`) { result[elem] = true; } - return result; - """ + when defined(nimphp): + asm """ + var $result = array(); + foreach (`a` as $elem=>$_) { $result[$elem] = true; } + foreach (`b` as $elem=>$_) { $result[$elem] = true; } + return $result; + """ + else: + asm """ + var result = {}; + for (var elem in `a`) { result[elem] = true; } + for (var elem in `b`) { result[elem] = true; } + return result; + """ proc SetMinus(a, b: int): int {.compilerproc, asmNoStackFrame.} = - asm """ - var result = {}; - for (var elem in `a`) { - if (!`b`[elem]) { result[elem] = true; } - } - return result; - """ + when defined(nimphp): + asm """ + $result = array(); + foreach (`a` as $elem=>$_) { + if (!isset(`b`[$elem])) { $result[$elem] = true; } + } + return $result; + """ + else: + asm """ + var result = {}; + for (var elem in `a`) { + if (!`b`[elem]) { result[elem] = true; } + } + return result; + """ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} = asm """ @@ -272,7 +386,15 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} = return 0; """ -proc cmp(x, y: string): int = return cmpStrings(x, y) +proc cmp(x, y: string): int = + when defined(nimphp): + asm """ + if(`x` < `y`) `result` = -1; + elseif (`x` > `y`) `result` = 1; + else `result` = 0; + """ + else: + return cmpStrings(x, y) proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} = asm """ @@ -307,7 +429,7 @@ elif defined(nodejs): console.log(buf); """ -else: +elif not defined(nimphp): proc ewriteln(x: cstring) = var node : JSRef {.emit: "`node` = document.getElementsByTagName('body')[0];".} @@ -333,77 +455,127 @@ else: # Arithmetic: proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ - var result = `a` + `b`; - if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); - return result; - """ + when defined(nimphp): + asm """ + return `a` + `b`; + """ + else: + asm """ + var result = `a` + `b`; + if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); + return result; + """ proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ - var result = `a` - `b`; - if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); - return result; - """ + when defined(nimphp): + asm """ + return `a` - `b`; + """ + else: + asm """ + var result = `a` - `b`; + if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); + return result; + """ proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ - var result = `a` * `b`; - if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); - return result; - """ + when defined(nimphp): + asm """ + return `a` * `b`; + """ + else: + asm """ + var result = `a` * `b`; + if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); + return result; + """ proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); - return Math.floor(`a` / `b`); - """ + when defined(nimphp): + asm """ + return floor(`a` / `b`); + """ + else: + asm """ + if (`b` == 0) `raiseDivByZero`(); + if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); + return Math.floor(`a` / `b`); + """ proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); - return Math.floor(`a` % `b`); - """ + when defined(nimphp): + asm """ + return `a` % `b`; + """ + else: + asm """ + if (`b` == 0) `raiseDivByZero`(); + if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); + return Math.floor(`a` % `b`); + """ proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ - var result = `a` + `b`; - if (result > 9223372036854775807 - || result < -9223372036854775808) `raiseOverflow`(); - return result; - """ + when defined(nimphp): + asm """ + return `a` + `b`; + """ + else: + asm """ + var result = `a` + `b`; + if (result > 9223372036854775807 + || result < -9223372036854775808) `raiseOverflow`(); + return result; + """ proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ - var result = `a` - `b`; - if (result > 9223372036854775807 - || result < -9223372036854775808) `raiseOverflow`(); - return result; - """ + when defined(nimphp): + asm """ + return `a` - `b`; + """ + else: + asm """ + var result = `a` - `b`; + if (result > 9223372036854775807 + || result < -9223372036854775808) `raiseOverflow`(); + return result; + """ proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ - var result = `a` * `b`; - if (result > 9223372036854775807 - || result < -9223372036854775808) `raiseOverflow`(); - return result; - """ + when defined(nimphp): + asm """ + return `a` * `b`; + """ + else: + asm """ + var result = `a` * `b`; + if (result > 9223372036854775807 + || result < -9223372036854775808) `raiseOverflow`(); + return result; + """ proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); - return Math.floor(`a` / `b`); - """ + when defined(nimphp): + asm """ + return floor(`a` / `b`); + """ + else: + asm """ + if (`b` == 0) `raiseDivByZero`(); + if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); + return Math.floor(`a` / `b`); + """ proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); - return Math.floor(`a` % `b`); - """ + when defined(nimphp): + asm """ + return `a` % `b`; + """ + else: + asm """ + if (`b` == 0) `raiseDivByZero`(); + if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); + return Math.floor(`a` % `b`); + """ proc negInt(a: int): int {.compilerproc.} = result = a*(-1) @@ -417,42 +589,6 @@ proc absInt(a: int): int {.compilerproc.} = proc absInt64(a: int64): int64 {.compilerproc.} = result = if a < 0: a*(-1) else: a -proc leU(a, b: int): bool {.compilerproc.} = - result = abs(a) <= abs(b) - -proc ltU(a, b: int): bool {.compilerproc.} = - result = abs(a) < abs(b) - -proc leU64(a, b: int64): bool {.compilerproc.} = - result = abs(a) <= abs(b) -proc ltU64(a, b: int64): bool {.compilerproc.} = - result = abs(a) < abs(b) - -proc addU(a, b: int): int {.compilerproc.} = - result = abs(a) + abs(b) -proc addU64(a, b: int64): int64 {.compilerproc.} = - result = abs(a) + abs(b) - -proc subU(a, b: int): int {.compilerproc.} = - result = abs(a) - abs(b) -proc subU64(a, b: int64): int64 {.compilerproc.} = - result = abs(a) - abs(b) - -proc mulU(a, b: int): int {.compilerproc.} = - result = abs(a) * abs(b) -proc mulU64(a, b: int64): int64 {.compilerproc.} = - result = abs(a) * abs(b) - -proc divU(a, b: int): int {.compilerproc.} = - result = abs(a) div abs(b) -proc divU64(a, b: int64): int64 {.compilerproc.} = - result = abs(a) div abs(b) - -proc modU(a, b: int): int {.compilerproc.} = - result = abs(a) mod abs(b) -proc modU64(a, b: int64): int64 {.compilerproc.} = - result = abs(a) mod abs(b) - proc ze*(a: int): int {.compilerproc.} = result = a @@ -592,11 +728,18 @@ proc genericReset(x: JSRef, ti: PNimType): JSRef {.compilerproc.} = proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {. asmNoStackFrame, compilerproc.} = # types are fake - asm """ - var result = new Array(`len`); - for (var i = 0; i < `len`; ++i) result[i] = nimCopy(null, `value`, `typ`); - return result; - """ + when defined(nimphp): + asm """ + $result = array(); + for ($i = 0; $i < `len`; $i++) $result[] = `value`; + return $result; + """ + else: + asm """ + var result = new Array(`len`); + for (var i = 0; i < `len`; ++i) result[i] = nimCopy(null, `value`, `typ`); + return result; + """ proc chckIndx(i, a, b: int): int {.compilerproc.} = if i >= a and i <= b: return i diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 1c13f3ff8..2e0fecd49 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -16,8 +16,8 @@ const debugGC = false # we wish to debug the GC... logGC = false - traceGC = false # extensive debugging - alwaysCycleGC = false + traceGC = defined(smokeCycles) # extensive debugging + alwaysCycleGC = defined(smokeCycles) alwaysGC = defined(fulldebug) # collect after every memory # allocation (for debugging) leakDetector = false diff --git a/lib/system/sysspawn.nim b/lib/system/sysspawn.nim index 7aef86df9..7da45b4dd 100644 --- a/lib/system/sysspawn.nim +++ b/lib/system/sysspawn.nim @@ -138,7 +138,7 @@ proc slave(w: ptr Worker) {.thread.} = const NumThreads = 4 var - workers: array[NumThreads, TThread[ptr Worker]] + workers: array[NumThreads, Thread[ptr Worker]] workersData: array[NumThreads, Worker] proc setup() = diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 4962186fb..d00964a6d 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -12,9 +12,18 @@ {.deadCodeElim:on.} +import dynlib + const useWinUnicode* = not defined(useWinAnsi) +when useWinUnicode: + type WinChar* = Utf16Char + {.deprecated: [TWinChar: WinChar].} +else: + type WinChar* = char + {.deprecated: [TWinChar: WinChar].} + type Handle* = int LONG* = int32 @@ -74,17 +83,18 @@ type nFileIndexHigh*: DWORD nFileIndexLow*: DWORD + OSVERSIONINFO* {.final, pure.} = object + dwOSVersionInfoSize*: DWORD + dwMajorVersion*: DWORD + dwMinorVersion*: DWORD + dwBuildNumber*: DWORD + dwPlatformId*: DWORD + szCSDVersion*: array[0..127, WinChar]; + {.deprecated: [THandle: Handle, TSECURITY_ATTRIBUTES: SECURITY_ATTRIBUTES, TSTARTUPINFO: STARTUPINFO, TPROCESS_INFORMATION: PROCESS_INFORMATION, TFILETIME: FILETIME, TBY_HANDLE_FILE_INFORMATION: BY_HANDLE_FILE_INFORMATION].} -when useWinUnicode: - type WinChar* = Utf16Char - {.deprecated: [TWinChar: WinChar].} -else: - type WinChar* = char - {.deprecated: [TWinChar: WinChar].} - const STARTF_USESHOWWINDOW* = 1'i32 STARTF_USESTDHANDLES* = 256'i32 @@ -117,6 +127,13 @@ const CREATE_NO_WINDOW* = 0x08000000'i32 +when useWinUnicode: + proc getVersionExW*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {.stdcall, dynlib: "kernel32", importc: "GetVersionExW".} +else: + proc getVersionExA*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {.stdcall, dynlib: "kernel32", importc: "GetVersionExA".} + +proc getVersion*(): DWORD {.stdcall, dynlib: "kernel32", importc: "GetVersion".} + proc closeHandle*(hObject: Handle): WINBOOL {.stdcall, dynlib: "kernel32", importc: "CloseHandle".} @@ -192,6 +209,9 @@ proc flushFileBuffers*(hFile: Handle): WINBOOL {.stdcall, dynlib: "kernel32", proc getLastError*(): int32 {.importc: "GetLastError", stdcall, dynlib: "kernel32".} +proc setLastError*(error: int32) {.importc: "SetLastError", + stdcall, dynlib: "kernel32".} + when useWinUnicode: proc formatMessageW*(dwFlags: int32, lpSource: pointer, dwMessageId, dwLanguageId: int32, @@ -289,9 +309,9 @@ when useWinUnicode: stdcall, dynlib: "kernel32", importc: "FindNextFileW".} else: proc findFirstFileA*(lpFileName: cstring, - lpFindFileData: var WIN32_FIND_DATA): THANDLE {. + lpFindFileData: var WIN32_FIND_DATA): Handle {. stdcall, dynlib: "kernel32", importc: "FindFirstFileA".} - proc findNextFileA*(hFindFile: THANDLE, + proc findNextFileA*(hFindFile: Handle, lpFindFileData: var WIN32_FIND_DATA): int32 {. stdcall, dynlib: "kernel32", importc: "FindNextFileA".} @@ -597,9 +617,6 @@ proc freeaddrinfo*(ai: ptr AddrInfo) {. proc inet_ntoa*(i: InAddr): cstring {. stdcall, importc, dynlib: ws2dll.} -proc inet_ntop*(family: cint, paddr: pointer, pStringBuffer: cstring, - stringBufSize: int32): cstring {.stdcall, importc, dynlib: ws2dll.} - const MAXIMUM_WAIT_OBJECTS* = 0x00000040 @@ -645,6 +662,7 @@ const const ERROR_ACCESS_DENIED* = 5 ERROR_HANDLE_EOF* = 38 + ERROR_BAD_ARGUMENTS* = 165 proc duplicateHandle*(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE, hTargetProcessHandle: HANDLE, @@ -667,7 +685,7 @@ else: proc createFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD, lpSecurityAttributes: pointer, dwCreationDisposition, dwFlagsAndAttributes: DWORD, - hTemplateFile: THANDLE): THANDLE {. + hTemplateFile: Handle): Handle {. stdcall, dynlib: "kernel32", importc: "CreateFileA".} proc deleteFileA*(pathName: cstring): int32 {. importc: "DeleteFileA", dynlib: "kernel32", stdcall.} @@ -697,10 +715,10 @@ proc createFileMappingW*(hFile: Handle, stdcall, dynlib: "kernel32", importc: "CreateFileMappingW".} when not useWinUnicode: - proc createFileMappingA*(hFile: THANDLE, + proc createFileMappingA*(hFile: Handle, lpFileMappingAttributes: pointer, flProtect, dwMaximumSizeHigh: DWORD, - dwMaximumSizeLow: DWORD, lpName: cstring): THANDLE {. + dwMaximumSizeLow: DWORD, lpName: cstring): Handle {. stdcall, dynlib: "kernel32", importc: "CreateFileMappingA".} proc unmapViewOfFile*(lpBaseAddress: pointer): WINBOOL {.stdcall, @@ -806,3 +824,54 @@ proc getSystemTimes*(lpIdleTime, lpKernelTime, proc getProcessTimes*(hProcess: Handle; lpCreationTime, lpExitTime, lpKernelTime, lpUserTime: var FILETIME): WINBOOL {.stdcall, dynlib: "kernel32", importc: "GetProcessTimes".} + +type inet_ntop_proc = proc(family: cint, paddr: pointer, pStringBuffer: cstring, + stringBufSize: int32): cstring {.stdcall.} + +var inet_ntop_real: inet_ntop_proc = nil + +let l = loadLib(ws2dll) +if l != nil: + inet_ntop_real = cast[inet_ntop_proc](symAddr(l, "inet_ntop")) + +proc WSAAddressToStringA(pAddr: ptr SockAddr, addrSize: DWORD, unused: pointer, pBuff: cstring, pBuffSize: ptr DWORD): cint {.stdcall, importc, dynlib: ws2dll.} +proc inet_ntop_emulated(family: cint, paddr: pointer, pStringBuffer: cstring, + stringBufSize: int32): cstring {.stdcall.} = + case family + of AF_INET: + var sa: Sockaddr_in + sa.sin_family = AF_INET + sa.sin_addr = cast[ptr InAddr](paddr)[] + var bs = stringBufSize.DWORD + let r = WSAAddressToStringA(cast[ptr SockAddr](sa.addr), sa.sizeof.DWORD, nil, pStringBuffer, bs.addr) + if r != 0: + result = nil + else: + result = pStringBuffer + of AF_INET6: + var sa: Sockaddr_in6 + sa.sin6_family = AF_INET6 + sa.sin6_addr = cast[ptr In6_addr](paddr)[] + var bs = stringBufSize.DWORD + let r = WSAAddressToStringA(cast[ptr SockAddr](sa.addr), sa.sizeof.DWORD, nil, pStringBuffer, bs.addr) + if r != 0: + result = nil + else: + result = pStringBuffer + else: + setLastError(ERROR_BAD_ARGUMENTS) + result = nil + +proc inet_ntop*(family: cint, paddr: pointer, pStringBuffer: cstring, + stringBufSize: int32): cstring {.stdcall.} = + var ver: OSVERSIONINFO + ver.dwOSVersionInfoSize = sizeof(ver).DWORD + let res = when useWinUnicode: getVersionExW(ver.addr) else: getVersionExA(ver.addr) + if res == 0: + result = nil + elif ver.dwMajorVersion >= 6: + if inet_ntop_real == nil: + quit("Can't load inet_ntop proc from " & ws2dll) + result = inet_ntop_real(family, paddr, pStringBuffer, stringBufSize) + else: + result = inet_ntop_emulated(family, paddr, pStringBuffer, stringBufSize) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index a227ac98c..05843e2d3 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -496,13 +496,12 @@ type data: array[MD5_LBLOCK, MD5_LONG] num: cuint -{.pragma: ic, importc: "$1".} {.push callconv:cdecl, dynlib:DLLUtilName.} -proc md5_Init*(c: var MD5_CTX): cint{.ic.} -proc md5_Update*(c: var MD5_CTX; data: pointer; len: csize): cint{.ic.} -proc md5_Final*(md: cstring; c: var MD5_CTX): cint{.ic.} -proc md5*(d: ptr cuchar; n: csize; md: ptr cuchar): ptr cuchar{.ic.} -proc md5_Transform*(c: var MD5_CTX; b: ptr cuchar){.ic.} +proc md5_Init*(c: var MD5_CTX): cint{.importc: "MD5_Init".} +proc md5_Update*(c: var MD5_CTX; data: pointer; len: csize): cint{.importc: "MD5_Update".} +proc md5_Final*(md: cstring; c: var MD5_CTX): cint{.importc: "MD5_Final".} +proc md5*(d: ptr cuchar; n: csize; md: ptr cuchar): ptr cuchar{.importc: "MD5".} +proc md5_Transform*(c: var MD5_CTX; b: ptr cuchar){.importc: "MD5_Transform".} {.pop.} from strutils import toHex,toLower |