Merge branch 'devel' of github.com:nim-lang/Nim into devel
This commit is contained in:
commit
090d22c715
18 changed files with 98 additions and 27 deletions
|
|
@ -24,6 +24,7 @@ environment:
|
||||||
# platform: x86
|
# platform: x86
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
- ps: Install-Product node 8 # node 8 or later is required to test js async stuff
|
||||||
- MKDIR %CD%\DIST
|
- MKDIR %CD%\DIST
|
||||||
- MKDIR %CD%\DIST\PCRE
|
- MKDIR %CD%\DIST\PCRE
|
||||||
- nuget install pcre -Verbosity quiet -Version 8.33.0.1 -OutputDirectory %CD%\DIST\PCRE
|
- nuget install pcre -Verbosity quiet -Version 8.33.0.1 -OutputDirectory %CD%\DIST\PCRE
|
||||||
|
|
|
||||||
|
|
@ -979,6 +979,7 @@ const
|
||||||
nkIdentKinds* = {nkIdent, nkSym, nkAccQuoted, nkOpenSymChoice,
|
nkIdentKinds* = {nkIdent, nkSym, nkAccQuoted, nkOpenSymChoice,
|
||||||
nkClosedSymChoice}
|
nkClosedSymChoice}
|
||||||
|
|
||||||
|
nkPragmaCallKinds* = {nkExprColonExpr, nkCall, nkCallStrLit}
|
||||||
nkLiterals* = {nkCharLit..nkTripleStrLit}
|
nkLiterals* = {nkCharLit..nkTripleStrLit}
|
||||||
nkLambdaKinds* = {nkLambda, nkDo}
|
nkLambdaKinds* = {nkLambda, nkDo}
|
||||||
declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef}
|
declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef}
|
||||||
|
|
|
||||||
|
|
@ -112,3 +112,4 @@ proc initDefines*() =
|
||||||
defineSymbol("nimNewRoof")
|
defineSymbol("nimNewRoof")
|
||||||
defineSymbol("nimHasRunnableExamples")
|
defineSymbol("nimHasRunnableExamples")
|
||||||
defineSymbol("nimNewDot")
|
defineSymbol("nimNewDot")
|
||||||
|
defineSymbol("nimHasNilChecks")
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ import
|
||||||
const
|
const
|
||||||
FirstCallConv* = wNimcall
|
FirstCallConv* = wNimcall
|
||||||
LastCallConv* = wNoconv
|
LastCallConv* = wNoconv
|
||||||
nkPragmaCallKinds = {nkExprColonExpr, nkCall, nkCallStrLit}
|
|
||||||
|
|
||||||
const
|
const
|
||||||
procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||||
|
|
|
||||||
|
|
@ -1143,7 +1143,7 @@ proc semProcAnnotation(c: PContext, prc: PNode;
|
||||||
if n == nil or n.kind == nkEmpty: return
|
if n == nil or n.kind == nkEmpty: return
|
||||||
for i in countup(0, n.len-1):
|
for i in countup(0, n.len-1):
|
||||||
var it = n.sons[i]
|
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)
|
let m = lookupMacro(c, key)
|
||||||
if m == nil:
|
if m == nil:
|
||||||
if key.kind == nkIdent and key.ident.id == ord(wDelegator):
|
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:
|
if prc[pragmasPos].kind != nkEmpty and prc[pragmasPos].len == 0:
|
||||||
prc.sons[pragmasPos] = emptyNode
|
prc.sons[pragmasPos] = emptyNode
|
||||||
|
|
||||||
if it.kind == nkExprColonExpr:
|
if it.kind in nkPragmaCallKinds and it.len > 1:
|
||||||
# pass pragma argument to the macro too:
|
# pass pragma arguments to the macro too:
|
||||||
x.add(it.sons[1])
|
for i in 1..<it.len:
|
||||||
|
x.add(it.sons[i])
|
||||||
x.add(prc)
|
x.add(prc)
|
||||||
|
|
||||||
# recursion assures that this works for multiple macro annotations too:
|
# recursion assures that this works for multiple macro annotations too:
|
||||||
result = semExpr(c, x)
|
result = semExpr(c, x)
|
||||||
# since a proc annotation can set pragmas, we process these here again.
|
# since a proc annotation can set pragmas, we process these here again.
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,9 @@ path="$lib/pure"
|
||||||
debugger:off
|
debugger:off
|
||||||
line_dir:off
|
line_dir:off
|
||||||
dead_code_elim:on
|
dead_code_elim:on
|
||||||
|
@if nimHasNilChecks:
|
||||||
|
nilchecks:off
|
||||||
|
@end
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@if release:
|
@if release:
|
||||||
|
|
|
||||||
|
|
@ -139,3 +139,7 @@ macro async*(arg: untyped): untyped =
|
||||||
proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importcpp: "(new Promise(#))".}
|
proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importcpp: "(new Promise(#))".}
|
||||||
## A helper for wrapping callback-based functions
|
## A helper for wrapping callback-based functions
|
||||||
## into promises and async procedures
|
## 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
|
||||||
|
|
|
||||||
6
lib/pure/async.nim
Normal file
6
lib/pure/async.nim
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
when defined(js):
|
||||||
|
import asyncjs
|
||||||
|
export asyncjs
|
||||||
|
else:
|
||||||
|
import asyncmacro, asyncfutures
|
||||||
|
export asyncmacro, asyncfutures
|
||||||
|
|
@ -277,6 +277,7 @@ template readInto(buf: pointer, size: int, socket: AsyncSocket,
|
||||||
flags: set[SocketFlag]): int =
|
flags: set[SocketFlag]): int =
|
||||||
## Reads **up to** ``size`` bytes from ``socket`` into ``buf``. Note that
|
## Reads **up to** ``size`` bytes from ``socket`` into ``buf``. Note that
|
||||||
## this is a template and not a proc.
|
## this is a template and not a proc.
|
||||||
|
assert(not socket.closed, "Cannot `recv` on a closed socket")
|
||||||
var res = 0
|
var res = 0
|
||||||
if socket.isSsl:
|
if socket.isSsl:
|
||||||
when defineSsl:
|
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
|
## Sends ``size`` bytes from ``buf`` to ``socket``. The returned future will complete once all
|
||||||
## data has been sent.
|
## data has been sent.
|
||||||
assert socket != nil
|
assert socket != nil
|
||||||
|
assert(not socket.closed, "Cannot `send` on a closed socket")
|
||||||
if socket.isSsl:
|
if socket.isSsl:
|
||||||
when defineSsl:
|
when defineSsl:
|
||||||
sslLoop(socket, flags,
|
sslLoop(socket, flags,
|
||||||
|
|
|
||||||
|
|
@ -868,6 +868,7 @@ proc close*(socket: Socket) =
|
||||||
socket.sslHandle = nil
|
socket.sslHandle = nil
|
||||||
|
|
||||||
socket.fd.close()
|
socket.fd.close()
|
||||||
|
socket.fd = osInvalidSocket
|
||||||
|
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
from posix import TCP_NODELAY
|
from posix import TCP_NODELAY
|
||||||
|
|
@ -1005,15 +1006,25 @@ proc select(readfd: Socket, timeout = 500): int =
|
||||||
var fds = @[readfd.fd]
|
var fds = @[readfd.fd]
|
||||||
result = select(fds, timeout)
|
result = select(fds, timeout)
|
||||||
|
|
||||||
|
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:
|
||||||
|
return SSLRead(socket.sslHandle, buffer, size)
|
||||||
|
|
||||||
|
return recv(socket.fd, buffer, size, flags)
|
||||||
|
|
||||||
proc readIntoBuf(socket: Socket, flags: int32): int =
|
proc readIntoBuf(socket: Socket, flags: int32): int =
|
||||||
result = 0
|
result = 0
|
||||||
when defineSsl:
|
result = uniRecv(socket, addr(socket.buffer), socket.buffer.high, flags)
|
||||||
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 result < 0:
|
if result < 0:
|
||||||
# Save it in case it gets reset (the Nim codegen occasionally may call
|
# Save it in case it gets reset (the Nim codegen occasionally may call
|
||||||
# Win API functions which reset it).
|
# Win API functions which reset it).
|
||||||
|
|
@ -1059,16 +1070,16 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect]
|
||||||
else:
|
else:
|
||||||
when defineSsl:
|
when defineSsl:
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
if socket.sslHasPeekChar:
|
if socket.sslHasPeekChar: # TODO: Merge this peek char mess into uniRecv
|
||||||
copyMem(data, addr(socket.sslPeekChar), 1)
|
copyMem(data, addr(socket.sslPeekChar), 1)
|
||||||
socket.sslHasPeekChar = false
|
socket.sslHasPeekChar = false
|
||||||
if size-1 > 0:
|
if size-1 > 0:
|
||||||
var d = cast[cstring](data)
|
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:
|
else:
|
||||||
result = 1
|
result = 1
|
||||||
else:
|
else:
|
||||||
result = SSLRead(socket.sslHandle, data, size)
|
result = uniRecv(socket, data, size.cint, 0'i32)
|
||||||
else:
|
else:
|
||||||
result = recv(socket.fd, data, size.cint, 0'i32)
|
result = recv(socket.fd, data, size.cint, 0'i32)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1145,7 +1156,11 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1,
|
||||||
##
|
##
|
||||||
## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
|
## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
|
||||||
data.setLen(size)
|
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:
|
if result < 0:
|
||||||
data.setLen(0)
|
data.setLen(0)
|
||||||
let lastError = getSocketError(socket)
|
let lastError = getSocketError(socket)
|
||||||
|
|
@ -1182,7 +1197,7 @@ proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
|
||||||
when defineSsl:
|
when defineSsl:
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
if not socket.sslHasPeekChar:
|
if not socket.sslHasPeekChar:
|
||||||
result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1)
|
result = uniRecv(socket, addr(socket.sslPeekChar), 1, 0'i32)
|
||||||
socket.sslHasPeekChar = true
|
socket.sslHasPeekChar = true
|
||||||
|
|
||||||
c = socket.sslPeekChar
|
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
|
## **Note**: This is a low-level version of ``send``. You likely should use
|
||||||
## the version below.
|
## the version below.
|
||||||
|
assert(not socket.isClosed, "Cannot `send` on a closed socket")
|
||||||
when defineSsl:
|
when defineSsl:
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
return SSLWrite(socket.sslHandle, cast[cstring](data), size)
|
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.
|
## which is defined below.
|
||||||
##
|
##
|
||||||
## **Note:** This proc is not available for SSL sockets.
|
## **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)
|
var aiList = getAddrInfo(address, port, af)
|
||||||
|
|
||||||
# try all possibilities:
|
# try all possibilities:
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
when defined(upcoming):
|
|
||||||
patchFile("stdlib", "asyncdispatch", "$lib/upcoming/asyncdispatch")
|
|
||||||
30
tests/async/tjsandnativeasync.nim
Normal file
30
tests/async/tjsandnativeasync.nim
Normal file
|
|
@ -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()
|
||||||
|
|
@ -13,11 +13,10 @@ proc MakeObj(): TTestObj =
|
||||||
result.x = "Hello"
|
result.x = "Hello"
|
||||||
|
|
||||||
for i in 1 .. 1_000_000:
|
for i in 1 .. 1_000_000:
|
||||||
when defined(gcMarkAndSweep):
|
when defined(gcMarkAndSweep) or defined(boehmgc):
|
||||||
GC_fullcollect()
|
GC_fullcollect()
|
||||||
var obj = MakeObj()
|
var obj = MakeObj()
|
||||||
if getOccupiedMem() > 300_000: quit("still a leak!")
|
if getOccupiedMem() > 300_000: quit("still a leak!")
|
||||||
# echo GC_getstatistics()
|
# echo GC_getstatistics()
|
||||||
|
|
||||||
echo "no leak: ", getOccupiedMem()
|
echo "no leak: ", getOccupiedMem()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ proc MakeObj(): TTestObj =
|
||||||
|
|
||||||
proc inProc() =
|
proc inProc() =
|
||||||
for i in 1 .. 1_000_000:
|
for i in 1 .. 1_000_000:
|
||||||
when defined(gcMarkAndSweep):
|
when defined(gcMarkAndSweep) or defined(boehmgc):
|
||||||
GC_fullcollect()
|
GC_fullcollect()
|
||||||
var obj: TTestObj
|
var obj: TTestObj
|
||||||
obj = MakeObj()
|
obj = MakeObj()
|
||||||
|
|
@ -24,5 +24,3 @@ proc inProc() =
|
||||||
|
|
||||||
inProc()
|
inProc()
|
||||||
echo "no leak: ", getOccupiedMem()
|
echo "no leak: ", getOccupiedMem()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ proc newPlus(a, b: ref TExpr): ref TPlusExpr =
|
||||||
result.b = b
|
result.b = b
|
||||||
result.op2 = $getOccupiedMem()
|
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:
|
for i in 0..100_000:
|
||||||
var s: array[0..11, ref TExpr]
|
var s: array[0..11, ref TExpr]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
discard """
|
discard """
|
||||||
disabled: true
|
|
||||||
output: '''
|
output: '''
|
||||||
x
|
x
|
||||||
e
|
e
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,11 @@ block: # A bit more advanced case
|
||||||
d {.alternativeKey("df", 5).}: float
|
d {.alternativeKey("df", 5).}: float
|
||||||
e {.alternativeKey(V = 5).}: seq[bool]
|
e {.alternativeKey(V = 5).}: seq[bool]
|
||||||
|
|
||||||
|
|
||||||
|
proc myproc(x: int, s: string) {.alternativeKey(V = 5), serializationKey"myprocSS".} =
|
||||||
|
echo x, s
|
||||||
|
|
||||||
|
|
||||||
var s: MySerializable
|
var s: MySerializable
|
||||||
|
|
||||||
const aDefVal = s.a.getCustomPragmaVal(defaultValue)
|
const aDefVal = s.a.getCustomPragmaVal(defaultValue)
|
||||||
|
|
@ -41,3 +46,8 @@ block: # A bit more advanced case
|
||||||
|
|
||||||
const cSerKey = getCustomPragmaVal(s.field.c, serializationKey)
|
const cSerKey = getCustomPragmaVal(s.field.c, serializationKey)
|
||||||
static: assert(cSerKey == "cc")
|
static: assert(cSerKey == "cc")
|
||||||
|
|
||||||
|
const procSerKey = getCustomPragmaVal(myproc, serializationKey)
|
||||||
|
static: assert(procSerKey == "myprocSS")
|
||||||
|
|
||||||
|
static: assert(hasCustomPragma(myproc, alternativeKey))
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,8 @@ proc jsTests(r: var TResults, cat: Category, options: string) =
|
||||||
"actiontable/tactiontable", "method/tmultim1",
|
"actiontable/tactiontable", "method/tmultim1",
|
||||||
"method/tmultim3", "method/tmultim4",
|
"method/tmultim3", "method/tmultim4",
|
||||||
"varres/tvarres0", "varres/tvarres3", "varres/tvarres4",
|
"varres/tvarres0", "varres/tvarres3", "varres/tvarres4",
|
||||||
"varres/tvartup", "misc/tints", "misc/tunsignedinc"]:
|
"varres/tvartup", "misc/tints", "misc/tunsignedinc",
|
||||||
|
"async/tjsandnativeasync"]:
|
||||||
test "tests/" & testfile & ".nim"
|
test "tests/" & testfile & ".nim"
|
||||||
|
|
||||||
for testfile in ["strutils", "json", "random", "times", "logging"]:
|
for testfile in ["strutils", "json", "random", "times", "logging"]:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue