diff options
-rw-r--r-- | appveyor.yml | 1 | ||||
-rw-r--r-- | compiler/ast.nim | 1 | ||||
-rw-r--r-- | compiler/condsyms.nim | 1 | ||||
-rw-r--r-- | compiler/pragmas.nim | 1 | ||||
-rw-r--r-- | compiler/semstmts.nim | 10 | ||||
-rw-r--r-- | config/nim.cfg | 3 | ||||
-rw-r--r-- | lib/js/asyncjs.nim | 4 | ||||
-rw-r--r-- | lib/pure/async.nim | 6 | ||||
-rw-r--r-- | lib/pure/asyncnet.nim | 2 | ||||
-rw-r--r-- | lib/pure/net.nim | 41 | ||||
-rw-r--r-- | tests/async/config.nims | 2 | ||||
-rw-r--r-- | tests/async/tjsandnativeasync.nim | 30 | ||||
-rw-r--r-- | tests/gc/gcleak.nim | 3 | ||||
-rw-r--r-- | tests/gc/gcleak2.nim | 4 | ||||
-rw-r--r-- | tests/gc/gcleak4.nim | 2 | ||||
-rw-r--r-- | tests/js/tasync.nim | 1 | ||||
-rw-r--r-- | tests/pragmas/tcustom_pragma.nim | 10 | ||||
-rw-r--r-- | tests/testament/categories.nim | 3 |
18 files changed, 98 insertions, 27 deletions
diff --git a/appveyor.yml b/appveyor.yml index be2cc50d3..a79d32e41 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,6 +24,7 @@ environment: # platform: x86 install: + - ps: Install-Product node 8 # node 8 or later is required to test js async stuff - MKDIR %CD%\DIST - MKDIR %CD%\DIST\PCRE - nuget install pcre -Verbosity quiet -Version 8.33.0.1 -OutputDirectory %CD%\DIST\PCRE diff --git a/compiler/ast.nim b/compiler/ast.nim index 69f2eb1c7..5c70bda18 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -979,6 +979,7 @@ const nkIdentKinds* = {nkIdent, nkSym, nkAccQuoted, nkOpenSymChoice, nkClosedSymChoice} + nkPragmaCallKinds* = {nkExprColonExpr, nkCall, nkCallStrLit} nkLiterals* = {nkCharLit..nkTripleStrLit} nkLambdaKinds* = {nkLambda, nkDo} declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef} diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index a52214e73..0be2899be 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -112,3 +112,4 @@ proc initDefines*() = defineSymbol("nimNewRoof") defineSymbol("nimHasRunnableExamples") defineSymbol("nimNewDot") + defineSymbol("nimHasNilChecks") diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index b6229796f..810c4c416 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -17,7 +17,6 @@ import const FirstCallConv* = wNimcall LastCallConv* = wNoconv - nkPragmaCallKinds = {nkExprColonExpr, nkCall, nkCallStrLit} const procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 339c02715..f46d314cc 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1143,7 +1143,7 @@ proc semProcAnnotation(c: PContext, prc: PNode; if n == nil or n.kind == nkEmpty: return for i in countup(0, n.len-1): var it = n.sons[i] - var key = if it.kind == nkExprColonExpr: it.sons[0] else: it + var key = if it.kind in nkPragmaCallKinds and it.len >= 1: it.sons[0] else: it let m = lookupMacro(c, key) if m == nil: if key.kind == nkIdent and key.ident.id == ord(wDelegator): @@ -1164,10 +1164,12 @@ proc semProcAnnotation(c: PContext, prc: PNode; if prc[pragmasPos].kind != nkEmpty and prc[pragmasPos].len == 0: prc.sons[pragmasPos] = emptyNode - if it.kind == nkExprColonExpr: - # pass pragma argument to the macro too: - x.add(it.sons[1]) + if it.kind in nkPragmaCallKinds and it.len > 1: + # pass pragma arguments to the macro too: + for i in 1..<it.len: + x.add(it.sons[i]) x.add(prc) + # recursion assures that this works for multiple macro annotations too: result = semExpr(c, x) # since a proc annotation can set pragmas, we process these here again. diff --git a/config/nim.cfg b/config/nim.cfg index a146c4ebf..9fddce90a 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -59,6 +59,9 @@ path="$lib/pure" debugger:off line_dir:off dead_code_elim:on + @if nimHasNilChecks: + nilchecks:off + @end @end @if release: diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim index ec410ee39..3c488dcfe 100644 --- a/lib/js/asyncjs.nim +++ b/lib/js/asyncjs.nim @@ -139,3 +139,7 @@ macro async*(arg: untyped): untyped = proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importcpp: "(new Promise(#))".} ## A helper for wrapping callback-based functions ## into promises and async procedures + +proc newPromise*(handler: proc(resolve: proc())): Future[void] {.importcpp: "(new Promise(#))".} + ## A helper for wrapping callback-based functions + ## into promises and async procedures diff --git a/lib/pure/async.nim b/lib/pure/async.nim new file mode 100644 index 000000000..97b29f81d --- /dev/null +++ b/lib/pure/async.nim @@ -0,0 +1,6 @@ +when defined(js): + import asyncjs + export asyncjs +else: + import asyncmacro, asyncfutures + export asyncmacro, asyncfutures diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 5be457d2a..93399bb40 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -277,6 +277,7 @@ template readInto(buf: pointer, size: int, socket: AsyncSocket, flags: set[SocketFlag]): int = ## Reads **up to** ``size`` bytes from ``socket`` into ``buf``. Note that ## this is a template and not a proc. + assert(not socket.closed, "Cannot `recv` on a closed socket") var res = 0 if socket.isSsl: when defineSsl: @@ -403,6 +404,7 @@ proc send*(socket: AsyncSocket, buf: pointer, size: int, ## Sends ``size`` bytes from ``buf`` to ``socket``. The returned future will complete once all ## data has been sent. assert socket != nil + assert(not socket.closed, "Cannot `send` on a closed socket") if socket.isSsl: when defineSsl: sslLoop(socket, flags, diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 083e70c8d..f348b7c51 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -868,6 +868,7 @@ proc close*(socket: Socket) = socket.sslHandle = nil socket.fd.close() + socket.fd = osInvalidSocket when defined(posix): from posix import TCP_NODELAY @@ -1005,15 +1006,25 @@ proc select(readfd: Socket, timeout = 500): int = var fds = @[readfd.fd] result = select(fds, timeout) -proc readIntoBuf(socket: Socket, flags: int32): int = +proc isClosed(socket: Socket): bool = + socket.fd == osInvalidSocket + +proc uniRecv(socket: Socket, buffer: pointer, size, flags: cint): int = + ## Handles SSL and non-ssl recv in a nice package. + ## + ## In particular handles the case where socket has been closed properly + ## for both SSL and non-ssl. result = 0 + assert(not socket.isClosed, "Cannot `recv` on a closed socket") when defineSsl: - if socket.isSSL: - result = SSLRead(socket.sslHandle, addr(socket.buffer), int(socket.buffer.high)) - else: - result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags) - else: - result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags) + if socket.isSsl: + return SSLRead(socket.sslHandle, buffer, size) + + return recv(socket.fd, buffer, size, flags) + +proc readIntoBuf(socket: Socket, flags: int32): int = + result = 0 + result = uniRecv(socket, addr(socket.buffer), socket.buffer.high, flags) if result < 0: # Save it in case it gets reset (the Nim codegen occasionally may call # Win API functions which reset it). @@ -1059,16 +1070,16 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect] else: when defineSsl: if socket.isSSL: - if socket.sslHasPeekChar: + if socket.sslHasPeekChar: # TODO: Merge this peek char mess into uniRecv copyMem(data, addr(socket.sslPeekChar), 1) socket.sslHasPeekChar = false if size-1 > 0: var d = cast[cstring](data) - result = SSLRead(socket.sslHandle, addr(d[1]), size-1) + 1 + result = uniRecv(socket, addr(d[1]), cint(size-1), 0'i32) + 1 else: result = 1 else: - result = SSLRead(socket.sslHandle, data, size) + result = uniRecv(socket, data, size.cint, 0'i32) else: result = recv(socket.fd, data, size.cint, 0'i32) else: @@ -1145,7 +1156,11 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1, ## ## **Warning**: Only the ``SafeDisconn`` flag is currently supported. data.setLen(size) - result = recv(socket, cstring(data), size, timeout) + result = + if timeout == -1: + recv(socket, cstring(data), size) + else: + recv(socket, cstring(data), size, timeout) if result < 0: data.setLen(0) let lastError = getSocketError(socket) @@ -1182,7 +1197,7 @@ proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} = when defineSsl: if socket.isSSL: if not socket.sslHasPeekChar: - result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1) + result = uniRecv(socket, addr(socket.sslPeekChar), 1, 0'i32) socket.sslHasPeekChar = true c = socket.sslPeekChar @@ -1316,6 +1331,7 @@ proc send*(socket: Socket, data: pointer, size: int): int {. ## ## **Note**: This is a low-level version of ``send``. You likely should use ## the version below. + assert(not socket.isClosed, "Cannot `send` on a closed socket") when defineSsl: if socket.isSSL: return SSLWrite(socket.sslHandle, cast[cstring](data), size) @@ -1360,6 +1376,7 @@ proc sendTo*(socket: Socket, address: string, port: Port, data: pointer, ## which is defined below. ## ## **Note:** This proc is not available for SSL sockets. + assert(not socket.isClosed, "Cannot `sendTo` on a closed socket") var aiList = getAddrInfo(address, port, af) # try all possibilities: diff --git a/tests/async/config.nims b/tests/async/config.nims deleted file mode 100644 index 97c2e0aa4..000000000 --- a/tests/async/config.nims +++ /dev/null @@ -1,2 +0,0 @@ -when defined(upcoming): - patchFile("stdlib", "asyncdispatch", "$lib/upcoming/asyncdispatch") diff --git a/tests/async/tjsandnativeasync.nim b/tests/async/tjsandnativeasync.nim new file mode 100644 index 000000000..45839899f --- /dev/null +++ b/tests/async/tjsandnativeasync.nim @@ -0,0 +1,30 @@ +discard """ + output: '''hi +bye''' +""" + +import async, times +when defined(js): + proc sleepAsync(t: int): Future[void] = + var promise = newPromise() do(resolve: proc()): + {.emit: """ + setTimeout(function(){ + `resolve`(); + }, `t`); + """.} + result = promise +else: + from asyncdispatch import sleepAsync, waitFor + +proc foo() {.async.} = + echo "hi" + var s = epochTime() + await sleepAsync(500) + var e = epochTime() + doAssert(e - s > 0.1) + echo "bye" + +when defined(js): + discard foo() +else: + waitFor foo() diff --git a/tests/gc/gcleak.nim b/tests/gc/gcleak.nim index 4e47db609..8852a8d91 100644 --- a/tests/gc/gcleak.nim +++ b/tests/gc/gcleak.nim @@ -13,11 +13,10 @@ proc MakeObj(): TTestObj = result.x = "Hello" for i in 1 .. 1_000_000: - when defined(gcMarkAndSweep): + when defined(gcMarkAndSweep) or defined(boehmgc): GC_fullcollect() var obj = MakeObj() if getOccupiedMem() > 300_000: quit("still a leak!") # echo GC_getstatistics() echo "no leak: ", getOccupiedMem() - diff --git a/tests/gc/gcleak2.nim b/tests/gc/gcleak2.nim index 101421683..facb8a008 100644 --- a/tests/gc/gcleak2.nim +++ b/tests/gc/gcleak2.nim @@ -16,7 +16,7 @@ proc MakeObj(): TTestObj = proc inProc() = for i in 1 .. 1_000_000: - when defined(gcMarkAndSweep): + when defined(gcMarkAndSweep) or defined(boehmgc): GC_fullcollect() var obj: TTestObj obj = MakeObj() @@ -24,5 +24,3 @@ proc inProc() = inProc() echo "no leak: ", getOccupiedMem() - - diff --git a/tests/gc/gcleak4.nim b/tests/gc/gcleak4.nim index d93a13854..e9b17e557 100644 --- a/tests/gc/gcleak4.nim +++ b/tests/gc/gcleak4.nim @@ -38,7 +38,7 @@ proc newPlus(a, b: ref TExpr): ref TPlusExpr = result.b = b result.op2 = $getOccupiedMem() -const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 500_000 +const Limit = when compileOption("gc", "markAndSweep") or compileOption("gc", "boehm"): 5*1024*1024 else: 500_000 for i in 0..100_000: var s: array[0..11, ref TExpr] diff --git a/tests/js/tasync.nim b/tests/js/tasync.nim index 34ef97b8b..76db38b27 100644 --- a/tests/js/tasync.nim +++ b/tests/js/tasync.nim @@ -1,5 +1,4 @@ discard """ - disabled: true output: ''' x e diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index a2380522f..415ae6a32 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -31,6 +31,11 @@ block: # A bit more advanced case d {.alternativeKey("df", 5).}: float e {.alternativeKey(V = 5).}: seq[bool] + + proc myproc(x: int, s: string) {.alternativeKey(V = 5), serializationKey"myprocSS".} = + echo x, s + + var s: MySerializable const aDefVal = s.a.getCustomPragmaVal(defaultValue) @@ -41,3 +46,8 @@ block: # A bit more advanced case const cSerKey = getCustomPragmaVal(s.field.c, serializationKey) static: assert(cSerKey == "cc") + + const procSerKey = getCustomPragmaVal(myproc, serializationKey) + static: assert(procSerKey == "myprocSS") + + static: assert(hasCustomPragma(myproc, alternativeKey)) diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 5c845fc5c..90468e627 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -226,7 +226,8 @@ proc jsTests(r: var TResults, cat: Category, options: string) = "actiontable/tactiontable", "method/tmultim1", "method/tmultim3", "method/tmultim4", "varres/tvarres0", "varres/tvarres3", "varres/tvarres4", - "varres/tvartup", "misc/tints", "misc/tunsignedinc"]: + "varres/tvartup", "misc/tints", "misc/tunsignedinc", + "async/tjsandnativeasync"]: test "tests/" & testfile & ".nim" for testfile in ["strutils", "json", "random", "times", "logging"]: |