diff options
Diffstat (limited to 'lib/system.nim')
-rw-r--r-- | lib/system.nim | 510 |
1 files changed, 155 insertions, 355 deletions
diff --git a/lib/system.nim b/lib/system.nim index 38f45ff7a..4c7fa83ca 100644 --- a/lib/system.nim +++ b/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.} - - # ----------------- 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 + when not defined(nimscript): + 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 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: enum|bool](x: var T, y: T) {. + magic: "Inc", noSideEffect, deprecated: "use `inc` instead".} -proc `-=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {. +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 |