Merge branch 'devel' of github.com:nim-lang/Nim into devel

This commit is contained in:
Araq
2017-12-27 10:34:31 +01:00
23 changed files with 419 additions and 59 deletions

View File

@@ -48,3 +48,5 @@ script:
- ./koch csource
- ./koch nimsuggest
# - nim c -r nimsuggest/tester
- ( ! grep -F '.. code-block' -l -r --include '*.html' --exclude contributing.html --exclude docgen.html --exclude tut2.html )
- ( ! grep -F '..code-block' -l -r --include '*.html' --exclude contributing.html --exclude docgen.html --exclude tut2.html )

View File

@@ -102,10 +102,12 @@ This now needs to be written as:
- Nim's ``rst2html`` command now supports the testing of code snippets via an RST
extension that we called ``:test:``::
```rst
.. code-block:: nim
:test:
# shows how the 'if' statement works
if true: echo "yes"
```
- The ``[]`` proc for strings now raises an ``IndexError`` exception when
the specified slice is out of bounds. See issue
[#6223](https://github.com/nim-lang/Nim/issues/6223) for more details.
@@ -130,7 +132,8 @@ This now needs to be written as:
- The ``random`` procs in ``random.nim`` have all been deprecated. Instead use
the new ``rand`` procs. The module now exports the state of the random
number generator as type ``Rand`` so multiple threads can easily use their
own random number generators that do not require locking.
own random number generators that do not require locking. For more information
about this rename see issue [#6934](https://github.com/nim-lang/Nim/issues/6934)
- The compiler is now more consistent in its treatment of ambiguous symbols:
Types that shadow procs and vice versa are marked as ambiguous (bug #6693).
- ``yield`` (or ``await`` which is mapped to ``yield``) never worked reliably
@@ -141,3 +144,25 @@ This now needs to be written as:
- codegenDecl pragma now works for the JavaScript backend. It returns an empty string for
function return type placeholders.
- Asynchronous programming for the JavaScript backend using the `asyncjs` module.
- Extra semantic checks for procs with noreturn pragma: return type is not allowed,
statements after call to noreturn procs are no longer allowed.
- Noreturn proc calls and raising exceptions branches are now skipped during common type
deduction in if and case expressions. The following code snippets now compile:
```nim
import strutils
let str = "Y"
let a = case str:
of "Y": true
of "N": false
else: raise newException(ValueError, "Invalid boolean")
let b = case str:
of nil, "": raise newException(ValueError, "Invalid boolean")
elif str.startsWith("Y"): true
elif str.startsWith("N"): false
else: false
let c = if str == "Y": true
elif str == "N": false
else:
echo "invalid bool"
quit("this is the end")
```

View File

@@ -611,7 +611,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "skipparentcfg":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optSkipParentConfigFiles)
of "genscript":
of "genscript", "gendeps":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optGenScript)
of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info)

View File

@@ -344,20 +344,20 @@ proc dfa(code: seq[Instr]) =
case code[i].kind
of use, useWithinCall: u[i].incl(code[i].sym.id)
of def: d[i].incl(code[i].sym.id)
of fork:
of fork, goto:
let d = i+code[i].dest
backrefs.add(d, i)
of goto: discard
var w = @[0]
var maxIters = 50
var someChange = true
while w.len > 0 and maxIters > 0 and someChange:
var takenGotos = initIntSet()
while w.len > 0 and maxIters > 0: # and someChange:
dec maxIters
var pc = w.pop() # w[^1]
var prevPc = -1
# this simulates a single linear control flow execution:
while pc < code.len and someChange:
while pc < code.len:
# according to the paper, it is better to shrink the working set here
# in this inner loop:
#let widx = w.find(pc)
@@ -386,17 +386,21 @@ proc dfa(code: seq[Instr]) =
if def notin d[prevPc]:
excl(intersect, def)
someChange = true
when defined(debugDfa):
echo "Excluding ", pc, " prev ", prevPc
assign d[pc], intersect
# our interpretation ![I!]:
prevPc = pc
when defined(debugDfa):
echo "looking at ", pc
case code[pc].kind
of goto:
# we must leave endless loops eventually:
#if someChange:
pc = pc + code[pc].dest
#else:
# inc pc
if not takenGotos.containsOrIncl(pc) or someChange:
pc = pc + code[pc].dest
else:
inc pc
of fork:
# we follow the next instruction but push the dest onto our "work" stack:
#if someChange:
@@ -405,6 +409,10 @@ proc dfa(code: seq[Instr]) =
of use, useWithinCall, def:
inc pc
when defined(useDfa) and defined(debugDfa):
for i in 0..<code.len:
echo "PC ", i, ": defs: ", d[i], "; uses ", u[i]
# now check the condition we're interested in:
for i in 0..<code.len:
case code[i].kind
@@ -508,7 +516,7 @@ proc dfaUnused(code: seq[Instr]) =
proc dataflowAnalysis*(s: PSym; body: PNode) =
var c = Con(code: @[], blocks: @[])
gen(c, body)
#echoCfg(c.code)
when defined(useDfa) and defined(debugDfa): echoCfg(c.code)
dfa(c.code)
proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =

View File

@@ -16,7 +16,7 @@ import
cgen, jsgen, json, nversion,
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
docgen2, service, parser, modules, ccgutils, sigmatch, ropes,
modulegraphs
modulegraphs, tables
from magicsys import systemModule, resetSysTypes
@@ -36,6 +36,9 @@ proc writeDepsFile(g: ModuleGraph; project: string) =
for m in g.modules:
if m != nil:
f.writeLine(toFullPath(m.position.int32))
for k in g.inclToMod.keys:
if g.getModule(k).isNil: # don't repeat includes which are also modules
f.writeLine(k.toFullPath)
f.close()
proc commandGenDepend(graph: ModuleGraph; cache: IdentCache) =
@@ -77,6 +80,8 @@ proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
let proj = changeFileExt(gProjectFull, "")
extccomp.callCCompiler(proj)
extccomp.writeJsonBuildInstructions(proj)
if optGenScript in gGlobalOptions:
writeDepsFile(graph, toGeneratedFile(proj, ""))
proc commandJsonScript(graph: ModuleGraph; cache: IdentCache) =
let proj = changeFileExt(gProjectFull, "")

View File

@@ -26,7 +26,8 @@ type
errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
errExceptionExpected, errExceptionAlreadyHandled,
errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine,
errInvalidNumberOfYieldExpr, errCannotReturnExpr,
errNoReturnWithReturnTypeNotAllowed, errAttemptToRedefine,
errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,
errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,
errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,
@@ -179,8 +180,9 @@ const
errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator",
errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expressions",
errCannotReturnExpr: "current routine cannot return an expression",
errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type",
errAttemptToRedefine: "redefinition of \'$1\'",
errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\' or \'continue'",
errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\', \'continue\' or proc call with noreturn pragma",
errStmtExpected: "statement expected",
errInvalidLabel: "\'$1\' is no label",
errInvalidCmdLineOption: "invalid command line option: \'$1\'",

View File

@@ -771,6 +771,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wNoreturn:
noVal(it)
incl(sym.flags, sfNoReturn)
if sym.typ[0] != nil:
localError(sym.ast[paramsPos][0].info, errNoReturnWithReturnTypeNotAllowed)
of wDynlib:
processDynLib(c, it, sym)
of wCompilerproc:

View File

@@ -165,6 +165,19 @@ proc commonType*(x, y: PType): PType =
result = newType(k, r.owner)
result.addSonSkipIntLit(r)
proc endsInNoReturn(n: PNode): bool =
# check if expr ends in raise exception or call of noreturn proc
var it = n
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
it = it.lastSon
result = it.kind == nkRaiseStmt or
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
proc commonType*(x: PType, y: PNode): PType =
# ignore exception raising branches in case/if expressions
if endsInNoReturn(y): return x
commonType(x, y.typ)
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info)
when defined(nimsuggest):

View File

@@ -165,14 +165,14 @@ proc semIf(c: PContext, n: PNode): PNode =
it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
when not newScopeForIf: openScope(c)
it.sons[1] = semExprBranch(c, it.sons[1])
typ = commonType(typ, it.sons[1].typ)
typ = commonType(typ, it.sons[1])
closeScope(c)
elif it.len == 1:
hasElse = true
it.sons[0] = semExprBranchScope(c, it.sons[0])
typ = commonType(typ, it.sons[0].typ)
typ = commonType(typ, it.sons[0])
else: illFormedAst(it)
if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
for it in n: discardCheck(c, it.lastSon)
result.kind = nkIfStmt
# propagate any enforced VoidContext:
@@ -180,7 +180,8 @@ proc semIf(c: PContext, n: PNode): PNode =
else:
for it in n:
let j = it.len-1
it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
if not endsInNoReturn(it.sons[j]):
it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
result.kind = nkIfExpr
result.typ = typ
@@ -213,7 +214,7 @@ proc semCase(c: PContext, n: PNode): PNode =
semCaseBranch(c, n, x, i, covered)
var last = sonsLen(x)-1
x.sons[last] = semExprBranchScope(c, x.sons[last])
typ = commonType(typ, x.sons[last].typ)
typ = commonType(typ, x.sons[last])
of nkElifBranch:
chckCovered = false
checkSonsLen(x, 2)
@@ -221,13 +222,13 @@ proc semCase(c: PContext, n: PNode): PNode =
x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0]))
when not newScopeForIf: openScope(c)
x.sons[1] = semExprBranch(c, x.sons[1])
typ = commonType(typ, x.sons[1].typ)
typ = commonType(typ, x.sons[1])
closeScope(c)
of nkElse:
chckCovered = false
checkSonsLen(x, 1)
x.sons[0] = semExprBranchScope(c, x.sons[0])
typ = commonType(typ, x.sons[0].typ)
typ = commonType(typ, x.sons[0])
hasElse = true
else:
illFormedAst(x)
@@ -237,7 +238,7 @@ proc semCase(c: PContext, n: PNode): PNode =
else:
localError(n.info, errNotAllCasesCovered)
closeScope(c)
if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
# propagate any enforced VoidContext:
if typ == enforceVoidContext:
@@ -246,7 +247,8 @@ proc semCase(c: PContext, n: PNode): PNode =
for i in 1..n.len-1:
var it = n.sons[i]
let j = it.len-1
it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
if not endsInNoReturn(it.sons[j]):
it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
result.typ = typ
proc semTry(c: PContext, n: PNode): PNode =
@@ -1851,8 +1853,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
else:
n.typ = n.sons[i].typ
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
case n.sons[i].kind
of LastBlockStmts:
if n.sons[i].kind in LastBlockStmts or
n.sons[i].kind in nkCallKinds and n.sons[i][0].kind == nkSym and sfNoReturn in n.sons[i][0].sym.flags:
for j in countup(i + 1, length - 1):
case n.sons[j].kind
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr,

View File

@@ -37,6 +37,7 @@ Advanced options:
--noMain do not generate a main procedure
--genScript generate a compile script (in the 'nimcache'
subdirectory named 'compile_$project$scriptext')
--genDeps generate a '.deps' file containing the dependencies
--os:SYMBOL set the target operating system (cross-compilation)
--cpu:SYMBOL set the target processor (cross-compilation)
--debuginfo enables debug information

View File

@@ -44,10 +44,10 @@
## resolve(game)
## return promise
##
## Forward definitions work properly, you just don't need to add the ``{.async.}`` pragma:
## Forward definitions work properly, you just need to always add the ``{.async.}`` pragma:
##
## .. code-block:: nim
## proc loadGame(name: string): Future[Game]
## proc loadGame(name: string): Future[Game] {.async.}
##
## JavaScript compatibility
## ~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -83,23 +83,54 @@ proc replaceReturn(node: var NimNode) =
replaceReturn(son)
inc z
proc isFutureVoid(node: NimNode): bool =
result = node.kind == nnkBracketExpr and
node[0].kind == nnkIdent and $node[0] == "Future" and
node[1].kind == nnkIdent and $node[1] == "void"
proc generateJsasync(arg: NimNode): NimNode =
assert arg.kind == nnkProcDef
result = arg
var isVoid = false
var jsResolveNode = ident("jsResolve")
if arg.params[0].kind == nnkEmpty:
result.params[0] = nnkBracketExpr.newTree(ident("Future"), ident("void"))
isVoid = true
elif isFutureVoid(arg.params[0]):
isVoid = true
var code = result.body
replaceReturn(code)
result.body = nnkStmtList.newTree()
var q = quote:
proc await[T](f: Future[T]): T {.importcpp: "(await #)".}
proc jsResolve[T](a: T): Future[T] {.importcpp: "#".}
result.body.add(q)
if len(code) > 0:
var awaitFunction = quote:
proc await[T](f: Future[T]): T {.importcpp: "(await #)".}
result.body.add(awaitFunction)
var resolve: NimNode
if isVoid:
resolve = quote:
var `jsResolveNode` {.importcpp: "undefined".}: Future[void]
else:
resolve = quote:
proc jsResolve[T](a: T): Future[T] {.importcpp: "#".}
result.body.add(resolve)
else:
result.body = newEmptyNode()
for child in code:
result.body.add(child)
if len(code) > 0 and isVoid:
var voidFix = quote:
return `jsResolveNode`
result.body.add(voidFix)
result.pragma = quote:
{.codegenDecl: "async function $2($3)".}
macro async*(arg: untyped): untyped =
## Macro which converts normal procedures into
## javascript-compatible async procedures

View File

@@ -1234,7 +1234,7 @@ else:
processBasicCallbacks(fd, writeList)
result = true
if Event.User in events or events == {Event.Error}:
if Event.User in events:
processBasicCallbacks(fd, readList)
custom = true
if rLength == 0:

View File

@@ -351,15 +351,19 @@ proc round*[T: float32|float64](x: T, places: int = 0): T =
result = round0(x*mult)/mult
when not defined(JS):
proc frexp*(x: float32, exponent: var int): float32 {.
proc c_frexp*(x: float32, exponent: var int32): float32 {.
importc: "frexp", header: "<math.h>".}
proc frexp*(x: float64, exponent: var int): float64 {.
proc c_frexp*(x: float64, exponent: var int32): float64 {.
importc: "frexp", header: "<math.h>".}
proc frexp*[T, U](x: T, exponent: var U): T =
## Split a number into mantissa and exponent.
## `frexp` calculates the mantissa m (a float greater than or equal to 0.5
## and less than 1) and the integer value n such that `x` (the original
## float value) equals m * 2**n. frexp stores n in `exponent` and returns
## m.
var exp: int32
result = c_frexp(x, exp)
exponent = exp
else:
proc frexp*[T: float32|float64](x: T, exponent: var int): T =
if x == 0.0:
@@ -368,9 +372,14 @@ else:
elif x < 0.0:
result = -frexp(-x, exponent)
else:
var ex = floor(log2(x))
exponent = round(ex)
var ex = trunc(log2(x))
exponent = int(ex)
result = x / pow(2.0, ex)
if abs(result) >= 1:
inc(exponent)
result = result / 2
if exponent == 1024 and result == 0.0:
result = 0.99999999999999988898
proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] =
## Breaks `x` into an integral and a fractional part.

View File

@@ -21,13 +21,41 @@
## ``nim c -r <testfile.nim>`` exits with 0 or 1
##
## Running a single test
## ---------------------
## =====================
##
## Simply specify the test name as a command line argument.
## Specify the test name as a command line argument.
##
## .. code::
##
## nim c -r test "my super awesome test name"
## nim c -r test "my test name" "another test"
##
## Multiple arguments can be used.
##
## Running a single test suite
## ===========================
##
## Specify the suite name delimited by ``"::"``.
##
## .. code::
##
## nim c -r test "my test name::"
##
## Selecting tests by pattern
## ==========================
##
## A single ``"*"`` can be used for globbing.
##
## Delimit the end of a suite name with ``"::"``.
##
## Tests matching **any** of the arguments are executed.
##
## .. code::
##
## nim c -r test fast_suite::mytest1 fast_suite::mytest2
## nim c -r test "fast_suite::mytest*"
## nim c -r test "auth*::" "crypto::hashing*"
## # Run suites starting with 'bug #' and standalone tests starting with '#'
## nim c -r test 'bug #*::' '::#*'
##
## Example
## -------
@@ -121,7 +149,7 @@ var
checkpoints {.threadvar.}: seq[string]
formatters {.threadvar.}: seq[OutputFormatter]
testsToRun {.threadvar.}: HashSet[string]
testsFilters {.threadvar.}: HashSet[string]
when declared(stdout):
abortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR")
@@ -300,22 +328,63 @@ method testEnded*(formatter: JUnitOutputFormatter, testResult: TestResult) =
method suiteEnded*(formatter: JUnitOutputFormatter) =
formatter.stream.writeLine("\t</testsuite>")
proc shouldRun(testName: string): bool =
if testsToRun.len == 0:
proc glob(matcher, filter: string): bool =
## Globbing using a single `*`. Empty `filter` matches everything.
if filter.len == 0:
return true
result = testName in testsToRun
if not filter.contains('*'):
return matcher == filter
let beforeAndAfter = filter.split('*', maxsplit=1)
if beforeAndAfter.len == 1:
# "foo*"
return matcher.startswith(beforeAndAfter[0])
if matcher.len < filter.len - 1:
return false # "12345" should not match "123*345"
return matcher.startsWith(beforeAndAfter[0]) and matcher.endsWith(beforeAndAfter[1])
proc matchFilter(suiteName, testName, filter: string): bool =
if filter == "":
return true
if testName == filter:
# corner case for tests containing "::" in their name
return true
let suiteAndTestFilters = filter.split("::", maxsplit=1)
if suiteAndTestFilters.len == 1:
# no suite specified
let test_f = suiteAndTestFilters[0]
return glob(testName, test_f)
return glob(suiteName, suiteAndTestFilters[0]) and glob(testName, suiteAndTestFilters[1])
when defined(testing): export matchFilter
proc shouldRun(currentSuiteName, testName: string): bool =
## Check if a test should be run by matching suiteName and testName against
## test filters.
if testsFilters.len == 0:
return true
for f in testsFilters:
if matchFilter(currentSuiteName, testName, f):
return true
return false
proc ensureInitialized() =
if formatters == nil:
formatters = @[OutputFormatter(defaultConsoleFormatter())]
if not testsToRun.isValid:
testsToRun.init()
if not testsFilters.isValid:
testsFilters.init()
when declared(paramCount):
# Read tests to run from the command line.
for i in 1 .. paramCount():
testsToRun.incl(paramStr(i))
testsFilters.incl(paramStr(i))
# These two procs are added as workarounds for
# https://github.com/nim-lang/Nim/issues/5549
@@ -395,7 +464,7 @@ template test*(name, body) {.dirty.} =
ensureInitialized()
if shouldRun(name):
if shouldRun(when declared(testSuiteName): testSuiteName else: "", name):
checkpoints = @[]
var testStatusIMPL {.inject.} = OK

View File

@@ -2916,7 +2916,10 @@ when not defined(JS): #and not defined(nimscript):
elif x > y: result = 1
else: result = 0
else:
result = int(c_strcmp(x, y))
let minlen = min(x.len, y.len)
result = int(c_memcmp(x.cstring, y.cstring, minlen.csize))
if result == 0:
result = x.len - y.len
when defined(nimscript):
proc readFile*(filename: string): string {.tags: [ReadIOEffect], benign.}

View File

@@ -63,7 +63,6 @@ proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
while x != subclass:
if x == nil:
sysFatal(ObjectConversionError, "invalid object conversion")
break
x = x.base
proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} =

View File

@@ -24,10 +24,10 @@ proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} =
if a == b: return 0
if a == nil: return -1
if b == nil: return 1
when defined(nimNoArrayToCstringConversion):
return c_strcmp(addr a.data, addr b.data)
else:
return c_strcmp(a.data, b.data)
let minlen = min(a.len, b.len)
result = c_memcmp(addr a.data, addr b.data, minlen.csize)
if result == 0:
result = a.len - b.len
proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
if a == b: return true

View File

@@ -36,5 +36,64 @@ var z = case i
echo z
#OUT ayyy
let str1 = "Y"
let str2 = "NN"
let a = case str1:
of "Y": true
of "N": false
else:
echo "no good"
quit("quiting")
let b = case str2:
of nil, "": raise newException(ValueError, "Invalid boolean")
elif str2[0] == 'Y': true
elif str2[0] == 'N': false
else: "error".quit(2)
doAssert(a == true)
doAssert(b == false)
var bb: bool
doassert(not compiles(
bb = case str2:
of nil, "": raise newException(ValueError, "Invalid boolean")
elif str.startsWith("Y"): true
elif str.startsWith("N"): false
))
doassert(not compiles(
bb = case str2:
of "Y": true
of "N": false
))
doassert(not compiles(
bb = case str2:
of "Y": true
of "N": raise newException(ValueError, "N not allowed")
))
doassert(not compiles(
bb = case str2:
of "Y": raise newException(ValueError, "Invalid Y")
else: raise newException(ValueError, "Invalid N")
))
doassert(not compiles(
bb = case str2:
of "Y":
raise newException(ValueError, "Invalid Y")
true
else: raise newException(ValueError, "Invalid")
))
doassert(not compiles(
bb = case str2:
of "Y":
"invalid Y".quit(3)
true
else: raise newException(ValueError, "Invalid")
))

View File

@@ -1,8 +1,8 @@
discard """
disabled: true
output: '''
0
x
e
'''
"""
@@ -10,16 +10,22 @@ import asyncjs
# demonstrate forward definition
# for js
proc y(e: int): Future[string]
proc y(e: int): Future[string] {.async.}
proc x(e: int) {.async.} =
proc e: int {.discardable.} =
echo "e"
return 2
proc x(e: int): Future[void] {.async.} =
var s = await y(e)
echo s
e()
proc y(e: int): Future[string] {.async.} =
echo 0
return "x"
if e > 0:
return await y(0)
else:
return "x"
discard x(2)

View File

@@ -0,0 +1,22 @@
discard """
ccodeCheck: "\\i @'__attribute__((noreturn))' .*"
"""
proc noret1*(i: int) {.noreturn.} =
echo i
proc noret2*(i: int): void {.noreturn.} =
echo i
var p {.used.}: proc(i: int): int
doAssert(not compiles(
p = proc(i: int): int {.noreturn.} = i # noreturn lambda returns int
))
doAssert(not compiles(
block:
noret1(5)
echo 1 # statement after noreturn
))

44
tests/stdlib/tfrexp1.nim Normal file
View File

@@ -0,0 +1,44 @@
discard """
targets: "js c c++"
output: '''ok'''
"""
import math
import strformat
const manualTest = false
proc frexp_test(lo, hi, step: float64) =
var exp: int
var frac: float64
var eps = 1e-15.float64
var x:float64 = lo
while x <= hi:
frac = frexp(x.float, exp)
let rslt = pow(2.0, float(exp)) * frac
doAssert(abs(rslt - x) < eps)
when manualTest:
echo fmt("x: {x:10.3f} exp: {exp:4d} frac: {frac:24.20f} check: {$(abs(rslt - x) < eps):-5s} {rslt: 9.3f}")
x += step
when manualTest:
var exp: int
var frac: float64
for flval in [1.7976931348623157e+308, -1.7976931348623157e+308, # max, min float64
3.4028234663852886e+38, -3.4028234663852886e+38, # max, min float32
4.9406564584124654e-324, -4.9406564584124654e-324, # smallest/largest positive/negative float64
1.4012984643248171e-45, -1.4012984643248171e-45, # smallest/largest positive/negative float32
2.2250738585072014e-308, 1.1754943508222875e-38]: # smallest normal float64/float32
frac = frexp(flval, exp)
echo fmt("{flval:25.16e}, {exp: 6d}, {frac: .20f} {frac * pow(2.0, float(exp)): .20e}")
frexp_test(-1000.0, 1000.0, 0.0125)
else:
frexp_test(-1000000.0, 1000000.0, 0.125)
echo "ok"

View File

@@ -56,4 +56,24 @@ proc test_string_slice() =
echo("OK")
proc test_string_cmp() =
let world = "hello\0world"
let earth = "hello\0earth"
let short = "hello\0"
let hello = "hello"
let goodbye = "goodbye"
doAssert world == world
doAssert world != earth
doAssert world != short
doAssert world != hello
doAssert world != goodbye
doAssert cmp(world, world) == 0
doAssert cmp(world, earth) > 0
doAssert cmp(world, short) > 0
doAssert cmp(world, hello) > 0
doAssert cmp(world, goodbye) > 0
test_string_slice()
test_string_cmp()

View File

@@ -13,6 +13,8 @@ discard """
[Suite] bug #5784
[Suite] test name filtering
'''
"""
@@ -120,3 +122,39 @@ suite "bug #5784":
field: int
var obj: Obj
check obj.isNil or obj.field == 0
when defined(testing):
suite "test name filtering":
test "test name":
check matchFilter("suite1", "foo", "")
check matchFilter("suite1", "foo", "foo")
check matchFilter("suite1", "foo", "::")
check matchFilter("suite1", "foo", "*")
check matchFilter("suite1", "foo", "::foo")
check matchFilter("suite1", "::foo", "::foo")
test "test name - glob":
check matchFilter("suite1", "foo", "f*")
check matchFilter("suite1", "foo", "*oo")
check matchFilter("suite1", "12345", "12*345")
check matchFilter("suite1", "q*wefoo", "q*wefoo")
check false == matchFilter("suite1", "foo", "::x")
check false == matchFilter("suite1", "foo", "::x*")
check false == matchFilter("suite1", "foo", "::*x")
# overlap
check false == matchFilter("suite1", "12345", "123*345")
check matchFilter("suite1", "ab*c::d*e::f", "ab*c::d*e::f")
test "suite name":
check matchFilter("suite1", "foo", "suite1::")
check false == matchFilter("suite1", "foo", "suite2::")
check matchFilter("suite1", "qwe::foo", "qwe::foo")
check matchFilter("suite1", "qwe::foo", "suite1::qwe::foo")
test "suite name - glob":
check matchFilter("suite1", "foo", "::*")
check matchFilter("suite1", "foo", "*::*")
check matchFilter("suite1", "foo", "*::foo")
check false == matchFilter("suite1", "foo", "*ite2::")
check matchFilter("suite1", "q**we::foo", "q**we::foo")
check matchFilter("suite1", "a::b*c::d*e", "a::b*c::d*e")