Merge branch 'devel' into araq-quirky-exceptions
This commit is contained in:
commit
0841c64a32
347 changed files with 18361 additions and 16065 deletions
508
lib/system.nim
508
lib/system.nim
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue