Merge branch 'devel' into araq-quirky-exceptions

This commit is contained in:
Andreas Rumpf 2019-02-08 17:18:17 +01:00
commit 0841c64a32
347 changed files with 18361 additions and 16065 deletions

View file

@ -118,6 +118,22 @@ proc defined*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.}
## # Do here programmer friendly expensive sanity checks.
## # Put here the normal code
when defined(nimHasRunnableExamples):
proc runnableExamples*(body: untyped) {.magic: "RunnableExamples".}
## A section you should use to mark `runnable example`:idx: code with.
##
## - In normal debug and release builds code within
## a ``runnableExamples`` section is ignored.
## - The documentation generator is aware of these examples and considers them
## part of the ``##`` doc comment. As the last step of documentation
## generation the examples are put into an ``$file_example.nim`` file,
## compiled and tested. The collected examples are
## put into their own module to ensure the examples do not refer to
## non-exported symbols.
else:
template runnableExamples*(body: untyped) =
discard
proc declared*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.}
## Special compile-time procedure that checks whether `x` is
## declared. `x` has to be an identifier or a qualified identifier.
@ -553,7 +569,12 @@ type
trace: string
else:
trace: seq[StackTraceEntry]
raiseId: uint # set when exception is raised
when defined(nimBoostrapCsources0_19_0):
# see #10315, bootstrap with `nim cpp` from csources gave error:
# error: no member named 'raise_id' in 'Exception'
raise_id: uint # set when exception is raised
else:
raiseId: uint # set when exception is raised
up: ref Exception # used for stacking exceptions. Not exported!
Defect* = object of Exception ## \
@ -590,7 +611,7 @@ type
## Raised when assertion is proved wrong.
##
## Usually the result of using the `assert() template <#assert>`_.
ValueError* = object of Defect ## \
ValueError* = object of CatchableError ## \
## Raised for string and object conversion errors.
KeyError* = object of ValueError ## \
## Raised if a key cannot be found in a table.
@ -1609,7 +1630,9 @@ else:
template sysAssert(cond: bool, msg: string) =
when defined(useSysAssert):
if not cond:
echo "[SYSASSERT] ", msg
cstderr.rawWrite "[SYSASSERT] "
cstderr.rawWrite msg
cstderr.rawWrite "\n"
quit 1
const hasAlloc = (hostOS != "standalone" or not defined(nogc)) and not defined(nimscript)
@ -1792,21 +1815,26 @@ proc toFloat*(i: int): float {.
proc toBiggestFloat*(i: BiggestInt): BiggestFloat {.
magic: "ToBiggestFloat", noSideEffect, importc: "toBiggestFloat".}
## converts an biggestint `i` into a ``biggestfloat``. If the conversion
## converts a biggestint `i` into a ``biggestfloat``. If the conversion
## fails, `ValueError` is raised. However, on most platforms the
## conversion cannot fail.
proc toInt*(f: float): int {.
magic: "ToInt", noSideEffect, importc: "toInt".}
magic: "ToInt", noSideEffect, importc: "toInt".} =
## converts a floating point number `f` into an ``int``. Conversion
## rounds `f` if it does not contain an integer value. If the conversion
## fails (because `f` is infinite for example), `ValueError` is raised.
## rounds `f` half away from 0, see https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero
## Note that some floating point numbers (e.g. infinity or even 1e19)
## cannot be accurately converted.
runnableExamples:
doAssert toInt(0.49) == 0
doAssert toInt(0.5) == 1
doAssert toInt(-0.5) == -1 ## rounding is symmetrical
proc toBiggestInt*(f: BiggestFloat): BiggestInt {.
magic: "ToBiggestInt", noSideEffect, importc: "toBiggestInt".}
## converts a biggestfloat `f` into a ``biggestint``. Conversion
## rounds `f` if it does not contain an integer value. If the conversion
## fails (because `f` is infinite for example), `ValueError` is raised.
magic: "ToBiggestInt", noSideEffect, importc: "toBiggestInt".} =
## Same as `toInt` but for BiggestFloat to ``BiggestInt``.
runnableExamples:
doAssert toBiggestInt(0.49) == 0
proc addQuitProc*(quitProc: proc() {.noconv.}) {.
importc: "atexit", header: "<stdlib.h>".}
@ -2648,19 +2676,28 @@ proc compiles*(x: untyped): bool {.magic: "Compiles", noSideEffect, compileTime.
## echo "'+' for integers is available"
discard
include "system/helpers" # for `lineInfoToString`, `isNamedTuple`
proc `$`*[T: tuple|object](x: T): string =
## generic ``$`` operator for tuples that is lifted from the components
## of `x`. Example:
##
## .. code-block:: nim
## $(23, 45) == "(Field0: 23, Field1: 45)"
## $(23, 45) == "(23, 45)"
## $(a: 23, b: 45) == "(a: 23, b: 45)"
## $() == "()"
result = "("
var firstElement = true
const isNamed = T is object or isNamedTuple(T)
when not isNamed:
var count = 0
for name, value in fieldPairs(x):
if not firstElement: result.add(", ")
result.add(name)
result.add(": ")
when isNamed:
result.add(name)
result.add(": ")
else:
count.inc
when compiles($value):
when value isnot string and value isnot seq and compiles(value.isNil):
if value.isNil: result.add "nil"
@ -2670,6 +2707,11 @@ proc `$`*[T: tuple|object](x: T): string =
firstElement = false
else:
result.add("...")
firstElement = false
when not isNamed:
if count == 1:
result.add(",") # $(1,) should print as the semantically legal (1,)
result.add(")")
proc collectionToString[T](x: T, prefix, separator, suffix: string): string =
@ -2767,8 +2809,8 @@ when not defined(nimscript) and hasAlloc:
when not defined(JS) and not defined(nimscript) and hasAlloc:
proc nimGC_setStackBottom*(theStackBottom: pointer) {.compilerRtl, noinline, benign.}
## Expands operating GC stack range to `theStackBottom`. Does nothing
## if current stack bottom is already lower than `theStackBottom`.
## Expands operating GC stack range to `theStackBottom`. Does nothing
## if current stack bottom is already lower than `theStackBottom`.
else:
template GC_disable* =
@ -3031,6 +3073,19 @@ else:
if x < 0: -x else: x
{.pop.}
when defined(nimNewRoof):
iterator `..<`*[T](a, b: T): T =
var i = T(a)
while i < b:
yield i
inc i
else:
iterator `..<`*[S, T](a: S, b: T): T =
var i = T(a)
while i < b:
yield i
inc i
when not defined(JS):
proc likelyProc(val: bool): bool {.importc: "likely", nodecl, nosideeffect.}
proc unlikelyProc(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
@ -3104,7 +3159,7 @@ when not defined(JS): #and not defined(nimscript):
proc initStackBottom() {.inline, compilerproc.} =
# WARNING: This is very fragile! An array size of 8 does not work on my
# Linux 64bit system. -- That's because the stack direction is the other
# way round.
# way around.
when declared(nimGC_setStackBottom):
var locals {.volatile.}: pointer
locals = addr(locals)
@ -3122,256 +3177,49 @@ when not defined(JS): #and not defined(nimscript):
strDesc = TNimType(size: sizeof(string), kind: tyString, flags: {ntfAcyclic})
{.pop.}
when not defined(nimscript):
include "system/ansi_c"
include "system/memory"
# ----------------- IO Part ------------------------------------------------
type
CFile {.importc: "FILE", header: "<stdio.h>",
final, incompletestruct.} = object
File* = ptr CFile ## The type representing a file handle.
FileMode* = enum ## The file mode when opening a file.
fmRead, ## Open the file for read access only.
fmWrite, ## Open the file for write access only.
## If the file does not exist, it will be
## created. Existing files will be cleared!
fmReadWrite, ## Open the file for read and write access.
## If the file does not exist, it will be
## created. Existing files will be cleared!
fmReadWriteExisting, ## Open the file for read and write access.
## If the file does not exist, it will not be
## created. The existing file will not be cleared.
fmAppend ## Open the file for writing only; append data
## at the end.
FileHandle* = cint ## type that represents an OS file handle; this is
## useful for low-level file access
include "system/ansi_c"
include "system/memory"
proc zeroMem(p: pointer, size: Natural) =
nimZeroMem(p, size)
when declared(memTrackerOp):
memTrackerOp("zeroMem", p, size)
proc copyMem(dest, source: pointer, size: Natural) =
nimCopyMem(dest, source, size)
when declared(memTrackerOp):
memTrackerOp("copyMem", dest, size)
proc moveMem(dest, source: pointer, size: Natural) =
c_memmove(dest, source, size)
when declared(memTrackerOp):
memTrackerOp("moveMem", dest, size)
proc equalMem(a, b: pointer, size: Natural): bool =
nimCmpMem(a, b, size) == 0
proc zeroMem(p: pointer, size: Natural) =
nimZeroMem(p, size)
when declared(memTrackerOp):
memTrackerOp("zeroMem", p, size)
proc copyMem(dest, source: pointer, size: Natural) =
nimCopyMem(dest, source, size)
when declared(memTrackerOp):
memTrackerOp("copyMem", dest, size)
proc moveMem(dest, source: pointer, size: Natural) =
c_memmove(dest, source, size)
when declared(memTrackerOp):
memTrackerOp("moveMem", dest, size)
proc equalMem(a, b: pointer, size: Natural): bool =
nimCmpMem(a, b, size) == 0
proc cmp(x, y: string): int =
when nimvm:
when defined(nimscript):
if x < y: result = -1
elif x > y: result = 1
else: result = 0
else:
let minlen = min(x.len, y.len)
result = int(nimCmpMem(x.cstring, y.cstring, minlen.csize))
if result == 0:
result = x.len - y.len
when defined(nimscript):
proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
## Opens a file named `filename` for reading, calls `readAll
## <#readAll>`_ and closes the file afterwards. Returns the string.
## Raises an IO exception in case of an error. If # you need to call
## this inside a compile time macro you can use `staticRead
## <#staticRead>`_.
proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.}
## Opens a file named `filename` for writing. Then writes the
## `content` completely to the file and closes the file afterwards.
## Raises an IO exception in case of an error.
when nimvm:
if x < y: result = -1
elif x > y: result = 1
else: result = 0
else:
let minlen = min(x.len, y.len)
result = int(nimCmpMem(x.cstring, y.cstring, minlen.csize))
if result == 0:
result = x.len - y.len
when not defined(nimscript) and hostOS != "standalone":
# text file handling:
var
stdin* {.importc: "stdin", header: "<stdio.h>".}: File
## The standard input stream.
stdout* {.importc: "stdout", header: "<stdio.h>".}: File
## The standard output stream.
stderr* {.importc: "stderr", header: "<stdio.h>".}: File
## The standard error stream.
when defined(windows):
# work-around C's sucking abstraction:
# BUGFIX: stdin and stdout should be binary files!
proc c_setmode(handle, mode: cint) {.
importc: when defined(bcc): "setmode" else: "_setmode",
header: "<io.h>".}
var
O_BINARY {.importc: "_O_BINARY", header:"<fcntl.h>".}: cint
# we use binary mode on Windows:
c_setmode(c_fileno(stdin), O_BINARY)
c_setmode(c_fileno(stdout), O_BINARY)
c_setmode(c_fileno(stderr), O_BINARY)
when defined(endb):
proc endbStep()
when defined(useStdoutAsStdmsg):
template stdmsg*: File = stdout
else:
template stdmsg*: File = stderr
## Template which expands to either stdout or stderr depending on
## `useStdoutAsStdmsg` compile-time switch.
proc open*(f: var File, filename: string,
mode: FileMode = fmRead, bufSize: int = -1): bool {.tags: [],
benign.}
## Opens a file named `filename` with given `mode`.
##
## Default mode is readonly. Returns true iff the file could be opened.
## This throws no exception if the file could not be opened.
proc open*(f: var File, filehandle: FileHandle,
mode: FileMode = fmRead): bool {.tags: [], benign.}
## Creates a ``File`` from a `filehandle` with given `mode`.
##
## Default mode is readonly. Returns true iff the file could be opened.
proc open*(filename: string,
mode: FileMode = fmRead, bufSize: int = -1): File =
## Opens a file named `filename` with given `mode`.
##
## Default mode is readonly. Raises an ``IO`` exception if the file
## could not be opened.
if not open(result, filename, mode, bufSize):
sysFatal(IOError, "cannot open: ", filename)
proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {.
tags: [], benign.}
## reopens the file `f` with given `filename` and `mode`. This
## is often used to redirect the `stdin`, `stdout` or `stderr`
## file variables.
##
## Default mode is readonly. Returns true iff the file could be reopened.
proc setStdIoUnbuffered*() {.tags: [], benign.}
## Configures `stdin`, `stdout` and `stderr` to be unbuffered.
proc close*(f: File) {.tags: [], gcsafe.}
## Closes the file.
proc endOfFile*(f: File): bool {.tags: [], benign.}
## Returns true iff `f` is at the end.
proc readChar*(f: File): char {.tags: [ReadIOEffect].}
## Reads a single character from the stream `f`. Should not be used in
## performance sensitive code.
proc flushFile*(f: File) {.tags: [WriteIOEffect].}
## Flushes `f`'s buffer.
proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], benign.}
## Reads all data from the stream `file`.
##
## Raises an IO exception in case of an error. It is an error if the
## current file position is not at the beginning of the file.
proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
## Opens a file named `filename` for reading.
##
## Then calls `readAll <#readAll>`_ and closes the file afterwards.
## Returns the string. Raises an IO exception in case of an error. If
## you need to call this inside a compile time macro you can use
## `staticRead <#staticRead>`_.
proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.}
## Opens a file named `filename` for writing. Then writes the
## `content` completely to the file and closes the file afterwards.
## Raises an IO exception in case of an error.
proc write*(f: File, r: float32) {.tags: [WriteIOEffect], benign.}
proc write*(f: File, i: int) {.tags: [WriteIOEffect], benign.}
proc write*(f: File, i: BiggestInt) {.tags: [WriteIOEffect], benign.}
proc write*(f: File, r: BiggestFloat) {.tags: [WriteIOEffect], benign.}
proc write*(f: File, s: string) {.tags: [WriteIOEffect], benign.}
proc write*(f: File, b: bool) {.tags: [WriteIOEffect], benign.}
proc write*(f: File, c: char) {.tags: [WriteIOEffect], benign.}
proc write*(f: File, c: cstring) {.tags: [WriteIOEffect], benign.}
proc write*(f: File, a: varargs[string, `$`]) {.tags: [WriteIOEffect], benign.}
## Writes a value to the file `f`. May throw an IO exception.
proc readLine*(f: File): TaintedString {.tags: [ReadIOEffect], benign.}
## reads a line of text from the file `f`. May throw an IO exception.
## A line of text may be delimited by ``LF`` or ``CRLF``. The newline
## character(s) are not part of the returned string.
proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
benign.}
## reads a line of text from the file `f` into `line`. May throw an IO
## exception.
## A line of text may be delimited by ``LF`` or ``CRLF``. The newline
## character(s) are not part of the returned string. Returns ``false``
## if the end of the file has been reached, ``true`` otherwise. If
## ``false`` is returned `line` contains no new data.
proc writeLine*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
tags: [WriteIOEffect], benign.}
## writes the values `x` to `f` and then writes "\\n".
## May throw an IO exception.
proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
## retrieves the file size (in bytes) of `f`.
proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {.
tags: [ReadIOEffect], benign.}
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
proc readChars*(f: File, a: var openArray[char], start, len: Natural): int {.
tags: [ReadIOEffect], benign.}
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
##
## **Warning:** The buffer `a` must be pre-allocated. This can be done
## using, for example, ``newString``.
proc readBuffer*(f: File, buffer: pointer, len: Natural): int {.
tags: [ReadIOEffect], benign.}
## reads `len` bytes into the buffer pointed to by `buffer`. Returns
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {.
tags: [WriteIOEffect], benign.}
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case
## of an error.
proc writeChars*(f: File, a: openArray[char], start, len: Natural): int {.
tags: [WriteIOEffect], benign.}
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case
## of an error.
proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {.
tags: [WriteIOEffect], benign.}
## writes the bytes of buffer pointed to by the parameter `buffer` to the
## file `f`. Returns the number of actual written bytes, which may be less
## than `len` in case of an error.
proc setFilePos*(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) {.benign.}
## sets the position of the file pointer that is used for read/write
## operations. The file's first byte has the index zero.
proc getFilePos*(f: File): int64 {.benign.}
## retrieves the current position of the file pointer that is used to
## read from the file `f`. The file's first byte has the index zero.
proc getFileHandle*(f: File): FileHandle
## returns the OS file handle of the file ``f``. This is only useful for
## platform specific programming.
when defined(gcDestructors) and not defined(nimscript):
include "core/strs"
include "core/seqs"
when declared(newSeq):
proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] =
@ -3444,6 +3292,10 @@ when not defined(JS): #and not defined(nimscript):
## allows you to override the behaviour of your application when CTRL+C
## is pressed. Only one such hook is supported.
when not defined(noSignalHandler) and not defined(useNimRtl):
proc unsetControlCHook*()
## reverts a call to setControlCHook
proc writeStackTrace*() {.tags: [], gcsafe.}
## writes the current stack trace to ``stderr``. This is only works
## for debug builds. Since it's usually used for debugging, this
@ -3460,10 +3312,6 @@ when not defined(JS): #and not defined(nimscript):
when defined(memtracker):
include "system/memtracker"
when defined(gcDestructors):
include "core/strs"
include "core/seqs"
when hostOS == "standalone":
include "system/embedded"
else:
@ -3517,47 +3365,8 @@ when not defined(JS): #and not defined(nimscript):
{.pop.}
when hasAlloc: include "system/strmantle"
when hostOS != "standalone": include "system/sysio"
when hasThreadSupport:
when hostOS != "standalone": include "system/channels"
else:
include "system/sysio"
when not defined(nimscript) and hostOS != "standalone":
iterator lines*(filename: string): TaintedString {.tags: [ReadIOEffect].} =
## Iterates over any line in the file named `filename`.
##
## If the file does not exist `IOError` is raised. The trailing newline
## character(s) are removed from the iterated lines. Example:
##
## .. code-block:: nim
## import strutils
##
## proc transformLetters(filename: string) =
## var buffer = ""
## for line in filename.lines:
## 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
iterator lines*(f: File): TaintedString {.tags: [ReadIOEffect].} =
## Iterate over any line in the file `f`.
##
## The trailing newline character(s) are removed from the iterated lines.
## Example:
##
## .. code-block:: nim
## proc countZeros(filename: File): tuple[lines, zeros: int] =
## for line in filename.lines:
## for letter in line:
## if letter == '0':
## result.zeros += 1
## result.lines += 1
var res = TaintedString(newStringOfCap(80))
while f.readLine(res): yield res
when not defined(nimscript) and hasAlloc:
when not defined(gcDestructors):
@ -3648,9 +3457,6 @@ elif defined(JS):
if x < y: return -1
return 1
when defined(nimffi):
include "system/sysio"
when not defined(nimNoArrayToString):
proc `$`*[T, IDX](x: array[IDX, T]): string =
## generic ``$`` operator for arrays that is lifted from the components
@ -3666,7 +3472,11 @@ proc `$`*[T](x: openarray[T]): string =
proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} =
## a shorthand for ``echo(errormsg); quit(errorcode)``.
echo(errormsg)
when defined(nimscript) or defined(js) or (hostOS == "standalone"):
echo errormsg
else:
cstderr.rawWrite(errormsg)
cstderr.rawWrite("\n")
quit(errorcode)
{.pop.} # checks
@ -3693,19 +3503,6 @@ template `..<`*(a, b: untyped): untyped =
## a shortcut for 'a .. (when b is BackwardsIndex: succ(b) else: pred(b))'.
a .. (when b is BackwardsIndex: succ(b) else: pred(b))
when defined(nimNewRoof):
iterator `..<`*[T](a, b: T): T =
var i = T(a)
while i < b:
yield i
inc i
else:
iterator `..<`*[S, T](a: S, b: T): T =
var i = T(a)
while i < b:
yield i
inc i
template spliceImpl(s, a, L, b: untyped): untyped =
# make room for additional elements or cut:
var shift = b.len - max(0,L) # ignore negative slice size
@ -3863,15 +3660,21 @@ proc gorgeEx*(command: string, input = "", cache = ""): tuple[output: string,
## Same as `gorge` but also returns the precious exit code.
discard
proc `+=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.
proc `+=`*[T: SomeInteger](x: var T, y: T) {.
magic: "Inc", noSideEffect.}
## Increments an ordinal
## Increments an integer
proc `-=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.
proc `+=`*[T: enum|bool](x: var T, y: T) {.
magic: "Inc", noSideEffect, deprecated: "use `inc` instead".}
proc `-=`*[T: SomeInteger](x: var T, y: T) {.
magic: "Dec", noSideEffect.}
## Decrements an ordinal
proc `*=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.
proc `-=`*[T: enum|bool](x: var T, y: T) {.
magic: "Dec", noSideEffect, deprecated: "0.20.0, use `dec` instead".}
proc `*=`*[T: SomeInteger](x: var T, y: T) {.
inline, noSideEffect.} =
## Binary `*=` operator for ordinals
x = x * y
@ -3949,7 +3752,7 @@ proc instantiationInfo*(index = -1, fullPaths = false): tuple[
template currentSourcePath*: string = instantiationInfo(-1, true).filename
## returns the full file-system path of the current source
proc raiseAssert*(msg: string) {.noinline.} =
proc raiseAssert*(msg: string) {.noinline, noReturn.} =
sysFatal(AssertionError, msg)
proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
@ -3959,8 +3762,6 @@ proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
tags: [].}
Hide(raiseAssert)(msg)
include "system/helpers" # for `lineInfoToString`
template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool]) =
const loc = $instantiationInfo(-1, true)
bind instantiationInfo
@ -4280,15 +4081,17 @@ proc `==`*(x, y: cstring): bool {.magic: "EqCString", noSideEffect,
when defined(nimNoNilSeqs2):
when not compileOption("nilseqs"):
when defined(nimHasUserErrors):
proc `==`*(x: string; y: type(nil)): bool {.
# bug #9149; ensure that 'type(nil)' does not match *too* well by using 'type(nil) | type(nil)'.
# Eventually (in 0.20?) we will be able to remove this hack completely.
proc `==`*(x: string; y: type(nil) | type(nil)): bool {.
error: "'nil' is now invalid for 'string'; compile with --nilseqs:on for a migration period".} =
discard
proc `==`*(x: type(nil); y: string): bool {.
proc `==`*(x: type(nil) | type(nil); y: string): bool {.
error: "'nil' is now invalid for 'string'; compile with --nilseqs:on for a migration period".} =
discard
else:
proc `==`*(x: string; y: type(nil)): bool {.error.} = discard
proc `==`*(x: type(nil); y: string): bool {.error.} = discard
proc `==`*(x: string; y: type(nil) | type(nil)): bool {.error.} = discard
proc `==`*(x: type(nil) | type(nil); y: string): bool {.error.} = discard
template closureScope*(body: untyped): untyped =
## Useful when creating a closure in a loop to capture local loop variables by
@ -4356,24 +4159,7 @@ when defined(windows) and appType == "console" and defined(nimSetUtf8CodePage):
importc: "SetConsoleOutputCP".}
discard setConsoleOutputCP(65001) # 65001 - utf-8 codepage
when defined(nimHasRunnableExamples):
proc runnableExamples*(body: untyped) {.magic: "RunnableExamples".}
## A section you should use to mark `runnable example`:idx: code with.
##
## - In normal debug and release builds code within
## a ``runnableExamples`` section is ignored.
## - The documentation generator is aware of these examples and considers them
## part of the ``##`` doc comment. As the last step of documentation
## generation the examples are put into an ``$file_example.nim`` file,
## compiled and tested. The collected examples are
## put into their own module to ensure the examples do not refer to
## non-exported symbols.
else:
template runnableExamples*(body: untyped) =
discard
template doAssertRaises*(exception, code: untyped): typed =
template doAssertRaises*(exception: typedesc, code: untyped): typed =
## Raises ``AssertionError`` if specified ``code`` does not raise the
## specified exception. Example:
##
@ -4381,16 +4167,24 @@ template doAssertRaises*(exception, code: untyped): typed =
## doAssertRaises(ValueError):
## raise newException(ValueError, "Hello World")
var wrong = false
try:
if true:
code
wrong = true
except exception:
discard
except Exception as exc:
raiseAssert(astToStr(exception) &
" wasn't raised, another error was raised instead by:\n"&
astToStr(code))
when Exception is exception:
try:
if true:
code
wrong = true
except Exception:
discard
else:
try:
if true:
code
wrong = true
except exception:
discard
except Exception:
raiseAssert(astToStr(exception) &
" wasn't raised, another error was raised instead by:\n"&
astToStr(code))
if wrong:
raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code))
@ -4410,7 +4204,7 @@ when defined(cpp) and appType != "lib" and
echo trace & "Error: unhandled exception: " & ex.msg &
" [" & $ex.name & "]\n"
else:
stderr.write trace & "Error: unhandled exception: " & ex.msg &
cstderr.rawWrite trace & "Error: unhandled exception: " & ex.msg &
" [" & $ex.name & "]\n"
quit 1
@ -4459,3 +4253,9 @@ proc `$`*(t: typedesc): string {.magic: "TypeTrait".} =
doAssert $(type(42)) == "int"
doAssert $(type("Foo")) == "string"
static: doAssert $(type(@['A', 'B'])) == "seq[char]"
import system/widestrs
export widestrs
import system/io
export io