diff options
-rw-r--r-- | lib/system.nim | 488 | ||||
-rw-r--r-- | lib/system/assertions.nim | 89 | ||||
-rw-r--r-- | lib/system/fatal.nim | 47 | ||||
-rw-r--r-- | lib/system/iterators.nim | 243 | ||||
-rw-r--r-- | nimsuggest/tests/tdot1.nim | 2 | ||||
-rw-r--r-- | nimsuggest/tests/tdot2.nim | 3 | ||||
-rw-r--r-- | tests/assert/tfailedassert_stacktrace.nim | 6 | ||||
-rw-r--r-- | tests/errmsgs/t9768.nim | 2 | ||||
-rw-r--r-- | tests/manyloc/standalone/panicoverride.nim | 4 |
9 files changed, 450 insertions, 434 deletions
diff --git a/lib/system.nim b/lib/system.nim index 59565d6c6..10720f2fc 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2214,6 +2214,12 @@ when defined(nimNewRoof): dotdotImpl(uint64) dotdotImpl(uint32) + iterator `..<`*[T](a, b: T): T {.inline.} = + var i = T(a) + while i < b: + yield i + inc i + else: iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} = ## Counts from ordinal value `a` up to `b` (inclusive) with the given @@ -2244,6 +2250,12 @@ else: yield res inc(res) + iterator `..<`*[S, T](a: S, b: T): T {.inline.} = + var i = T(a) + while i < b: + yield i + inc i + iterator `||`*[S, T](a: S, b: T, annotation: static string = "parallel for"): T {. inline, magic: "OmpParFor", sideEffect.} = @@ -2332,159 +2344,6 @@ proc len*[U: Ordinal; V: Ordinal](x: HSlice[U, V]): int {.noSideEffect, inline.} ## assert((5..2).len == 0) result = max(0, ord(x.b) - ord(x.a) + 1) -iterator items*[T](a: openArray[T]): T {.inline.} = - ## iterates over each item of `a`. - var i = 0 - while i < len(a): - yield a[i] - inc(i) - -iterator mitems*[T](a: var openArray[T]): var T {.inline.} = - ## iterates over each item of `a` so that you can modify the yielded value. - var i = 0 - while i < len(a): - yield a[i] - inc(i) - -iterator items*[IX, T](a: array[IX, T]): T {.inline.} = - ## iterates over each item of `a`. - var i = low(IX) - if i <= high(IX): - while true: - yield a[i] - if i >= high(IX): break - inc(i) - -iterator mitems*[IX, T](a: var array[IX, T]): var T {.inline.} = - ## iterates over each item of `a` so that you can modify the yielded value. - var i = low(IX) - if i <= high(IX): - while true: - yield a[i] - if i >= high(IX): break - inc(i) - -iterator items*[T](a: set[T]): T {.inline.} = - ## iterates over each element of `a`. `items` iterates only over the - ## elements that are really in the set (and not over the ones the set is - ## able to hold). - var i = low(T).int - while i <= high(T).int: - if T(i) in a: yield T(i) - inc(i) - -iterator items*(a: cstring): char {.inline.} = - ## iterates over each item of `a`. - when defined(js): - var i = 0 - var L = len(a) - while i < L: - yield a[i] - inc(i) - else: - var i = 0 - while a[i] != '\0': - yield a[i] - inc(i) - -iterator mitems*(a: var cstring): var char {.inline.} = - ## iterates over each item of `a` so that you can modify the yielded value. - var i = 0 - while a[i] != '\0': - yield a[i] - inc(i) - -iterator items*(E: typedesc[enum]): E = - ## iterates over the values of the enum ``E``. - for v in low(E)..high(E): - yield v - -iterator items*[T](s: HSlice[T, T]): T = - ## iterates over the slice `s`, yielding each value between `s.a` and `s.b` - ## (inclusively). - for x in s.a..s.b: - yield x - -iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} = - ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. - var i = 0 - while i < len(a): - yield (i, a[i]) - inc(i) - -iterator mpairs*[T](a: var openArray[T]): tuple[key:int, val:var T]{.inline.} = - ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. - ## ``a[index]`` can be modified. - var i = 0 - while i < len(a): - yield (i, a[i]) - inc(i) - -iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} = - ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. - var i = low(IX) - if i <= high(IX): - while true: - yield (i, a[i]) - if i >= high(IX): break - inc(i) - -iterator mpairs*[IX, T](a:var array[IX, T]):tuple[key:IX,val:var T] {.inline.} = - ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. - ## ``a[index]`` can be modified. - var i = low(IX) - if i <= high(IX): - while true: - yield (i, a[i]) - if i >= high(IX): break - inc(i) - -iterator pairs*[T](a: seq[T]): tuple[key: int, val: T] {.inline.} = - ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. - var i = 0 - while i < len(a): - yield (i, a[i]) - inc(i) - -iterator mpairs*[T](a: var seq[T]): tuple[key: int, val: var T] {.inline.} = - ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. - ## ``a[index]`` can be modified. - var i = 0 - while i < len(a): - yield (i, a[i]) - inc(i) - -iterator pairs*(a: string): tuple[key: int, val: char] {.inline.} = - ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. - var i = 0 - while i < len(a): - yield (i, a[i]) - inc(i) - -iterator mpairs*(a: var string): tuple[key: int, val: var char] {.inline.} = - ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. - ## ``a[index]`` can be modified. - var i = 0 - while i < len(a): - yield (i, a[i]) - inc(i) - -iterator pairs*(a: cstring): tuple[key: int, val: char] {.inline.} = - ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. - var i = 0 - while a[i] != '\0': - yield (i, a[i]) - inc(i) - -iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} = - ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. - ## ``a[index]`` can be modified. - var i = 0 - while a[i] != '\0': - yield (i, a[i]) - inc(i) - - when defined(nimNoNilSeqs2): when not compileOption("nilseqs"): {.pragma: nilError, error.} @@ -2599,6 +2458,53 @@ proc `==`*[T](x, y: seq[T]): bool {.noSideEffect.} = return true +proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.} + ## converts the AST of `x` into a string representation. This is very useful + ## for debugging. + +proc instantiationInfo*(index = -1, fullPaths = false): tuple[ + filename: string, line: int, column: int] {.magic: "InstantiationInfo", noSideEffect.} + ## provides access to the compiler's instantiation stack line information + ## of a template. + ## + ## While similar to the `caller info`:idx: of other languages, it is determined + ## at compile time. + ## + ## This proc is mostly useful for meta programming (eg. ``assert`` template) + ## to retrieve information about the current filename and line number. + ## Example: + ## + ## .. code-block:: nim + ## import strutils + ## + ## template testException(exception, code: untyped): typed = + ## try: + ## let pos = instantiationInfo() + ## discard(code) + ## echo "Test failure at $1:$2 with '$3'" % [pos.filename, + ## $pos.line, astToStr(code)] + ## assert false, "A test expecting failure succeeded?" + ## except exception: + ## discard + ## + ## proc tester(pos: int): int = + ## let + ## a = @[1, 2, 3] + ## result = a[pos] + ## + ## when isMainModule: + ## testException(IndexError, tester(30)) + ## testException(IndexError, tester(1)) + ## # --> Test failure at example.nim:20 with 'tester(1)' + + +import system/assertions +export assertions + +import system/iterators +export iterators + + proc find*[T, S](a: T, item: S): int {.inline.}= ## Returns the first index of `item` in `a` or -1 if not found. This requires ## appropriate `items` and `==` operations to work. @@ -2619,59 +2525,6 @@ proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} = result = s[L] setLen(s, L) -iterator fields*[T: tuple|object](x: T): RootObj {. - magic: "Fields", noSideEffect.} - ## iterates over every field of `x`. Warning: This really transforms - ## the 'for' and unrolls the loop. The current implementation also has a bug - ## that affects symbol binding in the loop body. -iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: untyped] {. - magic: "Fields", noSideEffect.} - ## iterates over every field of `x` and `y`. - ## Warning: This is really transforms the 'for' and unrolls the loop. - ## The current implementation also has a bug that affects symbol binding - ## in the loop body. -iterator fieldPairs*[T: tuple|object](x: T): RootObj {. - magic: "FieldPairs", noSideEffect.} - ## Iterates over every field of `x` returning their name and value. - ## - ## When you iterate over objects with different field types you have to use - ## the compile time ``when`` instead of a runtime ``if`` to select the code - ## you want to run for each type. To perform the comparison use the `is - ## operator <manual.html#generics-is-operator>`_. Example: - ## - ## .. code-block:: Nim - ## - ## type - ## Custom = object - ## foo: string - ## bar: bool - ## - ## proc `$`(x: Custom): string = - ## result = "Custom:" - ## for name, value in x.fieldPairs: - ## when value is bool: - ## result.add("\n\t" & name & " is " & $value) - ## else: - ## if value.isNil: - ## result.add("\n\t" & name & " (nil)") - ## else: - ## result.add("\n\t" & name & " '" & value & "'") - ## - ## Another way to do the same without ``when`` is to leave the task of - ## picking the appropriate code to a secondary proc which you overload for - ## each field type and pass the `value` to. - ## - ## Warning: This really transforms the 'for' and unrolls the loop. The - ## current implementation also has a bug that affects symbol binding in the - ## loop body. -iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[ - a, b: untyped] {. - magic: "FieldPairs", noSideEffect.} - ## iterates over every field of `x` and `y`. - ## Warning: This really transforms the 'for' and unrolls the loop. - ## The current implementation also has a bug that affects symbol binding - ## in the loop body. - proc `==`*[T: tuple|object](x, y: T): bool = ## generic ``==`` operator for tuples that is lifted from the components ## of `x` and `y`. @@ -2762,7 +2615,6 @@ proc collectionToString[T](x: T, prefix, separator, suffix: string): string = result.addQuoted(value) else: result.addQuoted(value) - result.add(suffix) proc `$`*[T](x: set[T]): string = @@ -2884,7 +2736,8 @@ when not defined(nimscript) and hasAlloc: {.warning: "GC_getStatistics is a no-op in JavaScript".} "" -template accumulateResult*(iter: untyped) {.deprecated: "use `sequtils.toSeq` instead (more hygienic, sometimes more efficient)".} = +template accumulateResult*(iter: untyped) {.deprecated: + "use `sequtils.toSeq` instead (more hygienic, sometimes more efficient)".} = ## helps to convert an iterator to a proc. ## See also `sequtils.toSeq` which is more hygienic and efficient. ## @@ -3032,55 +2885,15 @@ template newException*(exceptn: typedesc, message: string; e when hostOS == "standalone": - include "$projectpath/panicoverride" + proc nimToCStringConv(s: NimString): cstring {.compilerProc, inline.} = + if s == nil or s.len == 0: result = cstring"" + else: result = cstring(addr s.data) when not defined(js) and not defined(nimscript): include "system/ansi_c" when not declared(sysFatal): - {.push profiler: off.} - when hostOS == "standalone": - proc sysFatal(exceptn: typedesc, message: string) {.inline.} = - panic(message) - - proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} = - rawoutput(message) - panic(arg) - elif defined(nimQuirky) and not defined(nimscript): - proc name(t: typedesc): string {.magic: "TypeTrait".} - - proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} = - var buf = newStringOfCap(200) - add(buf, "Error: unhandled exception: ") - add(buf, message) - add(buf, arg) - add(buf, " [") - add(buf, name exceptn) - add(buf, "]") - cstderr.rawWrite buf - quit 1 - - proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} = - sysFatal(exceptn, message, "") - else: - proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} = - when declared(owned): - var e: owned(ref exceptn) - else: - var e: ref exceptn - new(e) - e.msg = message - raise e - - proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} = - when declared(owned): - var e: owned(ref exceptn) - else: - var e: ref exceptn - new(e) - e.msg = message & arg - raise e - {.pop.} + include "system/fatal" proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.} ## get type information for `x`. Ordinary code should not use this, but @@ -3109,18 +2922,6 @@ 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.} @@ -3745,86 +3546,9 @@ template `&=`*(x, y: typed) = when declared(File): template `&=`*(f: File, x: typed) = write(f, x) -proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.} - ## converts the AST of `x` into a string representation. This is very useful - ## for debugging. - -proc instantiationInfo*(index = -1, fullPaths = false): tuple[ - filename: string, line: int, column: int] {.magic: "InstantiationInfo", noSideEffect.} - ## provides access to the compiler's instantiation stack line information - ## of a template. - ## - ## While similar to the `caller info`:idx: of other languages, it is determined - ## at compile time. - ## - ## This proc is mostly useful for meta programming (eg. ``assert`` template) - ## to retrieve information about the current filename and line number. - ## Example: - ## - ## .. code-block:: nim - ## import strutils - ## - ## template testException(exception, code: untyped): typed = - ## try: - ## let pos = instantiationInfo() - ## discard(code) - ## echo "Test failure at $1:$2 with '$3'" % [pos.filename, - ## $pos.line, astToStr(code)] - ## assert false, "A test expecting failure succeeded?" - ## except exception: - ## discard - ## - ## proc tester(pos: int): int = - ## let - ## a = @[1, 2, 3] - ## result = a[pos] - ## - ## when isMainModule: - ## testException(IndexError, tester(30)) - ## testException(IndexError, tester(1)) - ## # --> Test failure at example.nim:20 with 'tester(1)' - template currentSourcePath*: string = instantiationInfo(-1, true).filename ## returns the full file-system path of the current source -proc raiseAssert*(msg: string) {.noinline, noReturn.} = - sysFatal(AssertionError, msg) - -proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = - # trick the compiler to not list ``AssertionError`` when called - # by ``assert``. - type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, - tags: [].} - Hide(raiseAssert)(msg) - -template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool]) = - const loc = $instantiationInfo(-1, true) - bind instantiationInfo - mixin failedAssertImpl - when enabled: - # for stacktrace; fixes #8928; Note: `fullPaths = true` is correct - # here, regardless of --excessiveStackTrace - {.line: instantiationInfo(fullPaths = true).}: - if not cond: - failedAssertImpl(loc & " `" & expr & "` " & msg) - -template assert*(cond: untyped, msg = "") = - ## Raises ``AssertionError`` with `msg` if `cond` is false. Note - ## that ``AssertionError`` is hidden from the effect system, so it doesn't - ## produce ``{.raises: [AssertionError].}``. This exception is only supposed - ## to be caught by unit testing frameworks. - ## - ## The compiler may not generate any code at all for ``assert`` if it is - ## advised to do so through the ``-d:release`` or ``--assertions:off`` - ## `command line switches <nimc.html#command-line-switches>`_. - const expr = astToStr(cond) - assertImpl(cond, msg, expr, compileOption("assertions")) - -template doAssert*(cond: untyped, msg = "") = - ## same as ``assert`` but is always turned on regardless of ``--assertions`` - const expr = astToStr(cond) - assertImpl(cond, msg, expr, true) - when compileOption("rangechecks"): template rangeCheck*(cond) = ## Helper for performing user-defined range checks. @@ -3834,62 +3558,9 @@ when compileOption("rangechecks"): else: template rangeCheck*(cond) = discard -iterator items*[T](a: seq[T]): T {.inline.} = - ## iterates over each item of `a`. - var i = 0 - let L = len(a) - while i < L: - yield a[i] - inc(i) - assert(len(a) == L, "seq modified while iterating over it") - -iterator mitems*[T](a: var seq[T]): var T {.inline.} = - ## iterates over each item of `a` so that you can modify the yielded value. - var i = 0 - let L = len(a) - while i < L: - yield a[i] - inc(i) - assert(len(a) == L, "seq modified while iterating over it") - -iterator items*(a: string): char {.inline.} = - ## iterates over each item of `a`. - var i = 0 - let L = len(a) - while i < L: - yield a[i] - inc(i) - assert(len(a) == L, "string modified while iterating over it") - -iterator mitems*(a: var string): var char {.inline.} = - ## iterates over each item of `a` so that you can modify the yielded value. - var i = 0 - let L = len(a) - while i < L: - yield a[i] - inc(i) - assert(len(a) == L, "string modified while iterating over it") - when not defined(nimhygiene): {.pragma: inject.} -template onFailedAssert*(msg, code: untyped): untyped {.dirty.} = - ## Sets an assertion failure handler that will intercept any assert - ## statements following `onFailedAssert` in the current module scope. - ## - ## .. code-block:: nim - ## # module-wide policy to change the failed assert - ## # exception type in order to include a lineinfo - ## onFailedAssert(msg): - ## var e = new(TMyError) - ## e.msg = msg - ## e.lineinfo = instantiationInfo(-2) - ## raise e - ## - template failedAssertImpl(msgIMPL: string): untyped {.dirty.} = - let msg = msgIMPL - code - proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} = ## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not ## perform deep copies of `s`. This is only useful for optimization @@ -4203,35 +3874,6 @@ when defined(windows) and appType == "console" and defined(nimSetUtf8CodePage): importc: "SetConsoleOutputCP".} discard setConsoleOutputCP(65001) # 65001 - utf-8 codepage -template doAssertRaises*(exception: typedesc, code: untyped): typed = - ## Raises ``AssertionError`` if specified ``code`` does not raise the - ## specified exception. Example: - ## - ## .. code-block:: nim - ## doAssertRaises(ValueError): - ## raise newException(ValueError, "Hello World") - var wrong = false - 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)) - when not defined(js): proc toOpenArray*[T](x: seq[T]; first, last: int): openarray[T] {. magic: "Slice".} diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim new file mode 100644 index 000000000..42a5b61d7 --- /dev/null +++ b/lib/system/assertions.nim @@ -0,0 +1,89 @@ +include "system/helpers" + +when not declared(sysFatal): + include "system/fatal" + + +proc raiseAssert*(msg: string) {.noinline, noReturn.} = + sysFatal(AssertionError, msg) + +proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = + # trick the compiler to not list ``AssertionError`` when called + # by ``assert``. + type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, + tags: [].} + Hide(raiseAssert)(msg) + +template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool]) = + const loc = $instantiationInfo(-1, true) + bind instantiationInfo + mixin failedAssertImpl + when enabled: + # for stacktrace; fixes #8928 ; Note: `fullPaths = true` is correct + # here, regardless of --excessiveStackTrace + {.line: instantiationInfo(fullPaths = true).}: + if not cond: + failedAssertImpl(loc & " `" & expr & "` " & msg) + +template assert*(cond: untyped, msg = "") = + ## Raises ``AssertionError`` with `msg` if `cond` is false. Note + ## that ``AssertionError`` is hidden from the effect system, so it doesn't + ## produce ``{.raises: [AssertionError].}``. This exception is only supposed + ## to be caught by unit testing frameworks. + ## + ## The compiler may not generate any code at all for ``assert`` if it is + ## advised to do so through the ``-d:release`` or ``--assertions:off`` + ## `command line switches <nimc.html#command-line-switches>`_. + const expr = astToStr(cond) + assertImpl(cond, msg, expr, compileOption("assertions")) + +template doAssert*(cond: untyped, msg = "") = + ## same as ``assert`` but is always turned on regardless of ``--assertions`` + const expr = astToStr(cond) + assertImpl(cond, msg, expr, true) + +template onFailedAssert*(msg, code: untyped): untyped {.dirty.} = + ## Sets an assertion failure handler that will intercept any assert + ## statements following `onFailedAssert` in the current module scope. + ## + ## .. code-block:: nim + ## # module-wide policy to change the failed assert + ## # exception type in order to include a lineinfo + ## onFailedAssert(msg): + ## var e = new(TMyError) + ## e.msg = msg + ## e.lineinfo = instantiationInfo(-2) + ## raise e + ## + template failedAssertImpl(msgIMPL: string): untyped {.dirty.} = + let msg = msgIMPL + code + +template doAssertRaises*(exception: typedesc, code: untyped): typed = + ## Raises ``AssertionError`` if specified ``code`` does not raise the + ## specified exception. Example: + ## + ## .. code-block:: nim + ## doAssertRaises(ValueError): + ## raise newException(ValueError, "Hello World") + var wrong = false + 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)) diff --git a/lib/system/fatal.nim b/lib/system/fatal.nim new file mode 100644 index 000000000..100b6d482 --- /dev/null +++ b/lib/system/fatal.nim @@ -0,0 +1,47 @@ +{.push profiler: off.} +when hostOS == "standalone": + include "$projectpath/panicoverride" + + proc sysFatal(exceptn: typedesc, message: string) {.inline.} = + panic(message) + + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} = + rawoutput(message) + panic(arg) + +elif defined(nimQuirky) and not defined(nimscript): + proc name(t: typedesc): string {.magic: "TypeTrait".} + + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} = + var buf = newStringOfCap(200) + add(buf, "Error: unhandled exception: ") + add(buf, message) + add(buf, arg) + add(buf, " [") + add(buf, name exceptn) + add(buf, "]") + cstderr.rawWrite buf + quit 1 + + proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} = + sysFatal(exceptn, message, "") + +else: + proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} = + when declared(owned): + var e: owned(ref exceptn) + else: + var e: ref exceptn + new(e) + e.msg = message + raise e + + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} = + when declared(owned): + var e: owned(ref exceptn) + else: + var e: ref exceptn + new(e) + e.msg = message & arg + raise e +{.pop.} diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim new file mode 100644 index 000000000..2812db69e --- /dev/null +++ b/lib/system/iterators.nim @@ -0,0 +1,243 @@ +iterator items*[T](a: openArray[T]): T {.inline.} = + ## iterates over each item of `a`. + var i = 0 + while i < len(a): + yield a[i] + inc(i) + +iterator mitems*[T](a: var openArray[T]): var T {.inline.} = + ## iterates over each item of `a` so that you can modify the yielded value. + var i = 0 + while i < len(a): + yield a[i] + inc(i) + +iterator items*[IX, T](a: array[IX, T]): T {.inline.} = + ## iterates over each item of `a`. + var i = low(IX) + if i <= high(IX): + while true: + yield a[i] + if i >= high(IX): break + inc(i) + +iterator mitems*[IX, T](a: var array[IX, T]): var T {.inline.} = + ## iterates over each item of `a` so that you can modify the yielded value. + var i = low(IX) + if i <= high(IX): + while true: + yield a[i] + if i >= high(IX): break + inc(i) + +iterator items*[T](a: set[T]): T {.inline.} = + ## iterates over each element of `a`. `items` iterates only over the + ## elements that are really in the set (and not over the ones the set is + ## able to hold). + var i = low(T).int + while i <= high(T).int: + if T(i) in a: yield T(i) + inc(i) + +iterator items*(a: cstring): char {.inline.} = + ## iterates over each item of `a`. + when defined(js): + var i = 0 + var L = len(a) + while i < L: + yield a[i] + inc(i) + else: + var i = 0 + while a[i] != '\0': + yield a[i] + inc(i) + +iterator mitems*(a: var cstring): var char {.inline.} = + ## iterates over each item of `a` so that you can modify the yielded value. + var i = 0 + while a[i] != '\0': + yield a[i] + inc(i) + +iterator items*(E: typedesc[enum]): E = + ## iterates over the values of the enum ``E``. + for v in low(E)..high(E): + yield v + +iterator items*[T](s: HSlice[T, T]): T = + ## iterates over the slice `s`, yielding each value between `s.a` and `s.b` + ## (inclusively). + for x in s.a..s.b: + yield x + +iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + var i = 0 + while i < len(a): + yield (i, a[i]) + inc(i) + +iterator mpairs*[T](a: var openArray[T]): tuple[key:int, val:var T]{.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. + var i = 0 + while i < len(a): + yield (i, a[i]) + inc(i) + +iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + var i = low(IX) + if i <= high(IX): + while true: + yield (i, a[i]) + if i >= high(IX): break + inc(i) + +iterator mpairs*[IX, T](a:var array[IX, T]):tuple[key:IX,val:var T] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. + var i = low(IX) + if i <= high(IX): + while true: + yield (i, a[i]) + if i >= high(IX): break + inc(i) + +iterator pairs*[T](a: seq[T]): tuple[key: int, val: T] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + var i = 0 + while i < len(a): + yield (i, a[i]) + inc(i) + +iterator mpairs*[T](a: var seq[T]): tuple[key: int, val: var T] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. + var i = 0 + while i < len(a): + yield (i, a[i]) + inc(i) + +iterator pairs*(a: string): tuple[key: int, val: char] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + var i = 0 + while i < len(a): + yield (i, a[i]) + inc(i) + +iterator mpairs*(a: var string): tuple[key: int, val: var char] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. + var i = 0 + while i < len(a): + yield (i, a[i]) + inc(i) + +iterator pairs*(a: cstring): tuple[key: int, val: char] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + var i = 0 + while a[i] != '\0': + yield (i, a[i]) + inc(i) + +iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. + var i = 0 + while a[i] != '\0': + yield (i, a[i]) + inc(i) + +iterator items*[T](a: seq[T]): T {.inline.} = + ## iterates over each item of `a`. + var i = 0 + let L = len(a) + while i < L: + yield a[i] + inc(i) + assert(len(a) == L, "seq modified while iterating over it") + +iterator mitems*[T](a: var seq[T]): var T {.inline.} = + ## iterates over each item of `a` so that you can modify the yielded value. + var i = 0 + let L = len(a) + while i < L: + yield a[i] + inc(i) + assert(len(a) == L, "seq modified while iterating over it") + +iterator items*(a: string): char {.inline.} = + ## iterates over each item of `a`. + var i = 0 + let L = len(a) + while i < L: + yield a[i] + inc(i) + assert(len(a) == L, "string modified while iterating over it") + +iterator mitems*(a: var string): var char {.inline.} = + ## iterates over each item of `a` so that you can modify the yielded value. + var i = 0 + let L = len(a) + while i < L: + yield a[i] + inc(i) + assert(len(a) == L, "string modified while iterating over it") + +iterator fields*[T: tuple|object](x: T): RootObj {. + magic: "Fields", noSideEffect.} + ## iterates over every field of `x`. Warning: This really transforms + ## the 'for' and unrolls the loop. The current implementation also has a bug + ## that affects symbol binding in the loop body. + +iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: untyped] {. + magic: "Fields", noSideEffect.} + ## iterates over every field of `x` and `y`. + ## Warning: This is really transforms the 'for' and unrolls the loop. + ## The current implementation also has a bug that affects symbol binding + ## in the loop body. + +iterator fieldPairs*[T: tuple|object](x: T): RootObj {. + magic: "FieldPairs", noSideEffect.} + ## Iterates over every field of `x` returning their name and value. + ## + ## When you iterate over objects with different field types you have to use + ## the compile time ``when`` instead of a runtime ``if`` to select the code + ## you want to run for each type. To perform the comparison use the `is + ## operator <manual.html#generics-is-operator>`_. Example: + ## + ## .. code-block:: Nim + ## + ## type + ## Custom = object + ## foo: string + ## bar: bool + ## + ## proc `$`(x: Custom): string = + ## result = "Custom:" + ## for name, value in x.fieldPairs: + ## when value is bool: + ## result.add("\n\t" & name & " is " & $value) + ## else: + ## if value.isNil: + ## result.add("\n\t" & name & " (nil)") + ## else: + ## result.add("\n\t" & name & " '" & value & "'") + ## + ## Another way to do the same without ``when`` is to leave the task of + ## picking the appropriate code to a secondary proc which you overload for + ## each field type and pass the `value` to. + ## + ## Warning: This really transforms the 'for' and unrolls the loop. The + ## current implementation also has a bug that affects symbol binding in the + ## loop body. + +iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[ + a, b: untyped] {. + magic: "FieldPairs", noSideEffect.} + ## iterates over every field of `x` and `y`. + ## Warning: This really transforms the 'for' and unrolls the loop. + ## The current implementation also has a bug that affects symbol binding + ## in the loop body. diff --git a/nimsuggest/tests/tdot1.nim b/nimsuggest/tests/tdot1.nim index 9ac92f8a5..c64e1138c 100644 --- a/nimsuggest/tests/tdot1.nim +++ b/nimsuggest/tests/tdot1.nim @@ -1,5 +1,5 @@ discard """ -$nimsuggest --tester $file +$nimsuggest --tester --maxresults:3 $file >sug $1 sug;;skField;;x;;int;;$file;;11;;4;;"";;100;;None sug;;skField;;y;;int;;$file;;11;;7;;"";;100;;None diff --git a/nimsuggest/tests/tdot2.nim b/nimsuggest/tests/tdot2.nim index f02b5cf16..1a2df9ba2 100644 --- a/nimsuggest/tests/tdot2.nim +++ b/nimsuggest/tests/tdot2.nim @@ -15,7 +15,7 @@ proc main(f: Foo) = # the tester supports the spec section at the bottom of the file and # this way, the line numbers more often stay the same discard """ -$nimsuggest --tester $file +$nimsuggest --tester --maxresults:3 $file >sug $1 sug;;skField;;x;;int;;$file;;8;;4;;"";;100;;None sug;;skField;;y;;int;;$file;;8;;7;;"";;100;;None @@ -25,5 +25,4 @@ sug;;skProc;;tdot2.main;;proc (f: Foo);;$file;;12;;5;;"";;100;;None sug;;skField;;x;;int;;$file;;8;;4;;"";;100;;None sug;;skField;;y;;int;;$file;;8;;7;;"";;100;;None sug;;skField;;z;;string;;$file;;10;;6;;"";;100;;None -sug;;skProc;;tdot2.main;;proc (f: Foo);;$file;;12;;5;;"";;100;;None """ diff --git a/tests/assert/tfailedassert_stacktrace.nim b/tests/assert/tfailedassert_stacktrace.nim index 6505f189c..b5da3eb43 100644 --- a/tests/assert/tfailedassert_stacktrace.nim +++ b/tests/assert/tfailedassert_stacktrace.nim @@ -5,9 +5,9 @@ discard """ const expected = """ tfailedassert_stacktrace.nim(34) tfailedassert_stacktrace tfailedassert_stacktrace.nim(33) foo -system.nim(*) failedAssertImpl -system.nim(*) raiseAssert -system.nim(*) sysFatal""" +assertions.nim(*) failedAssertImpl +assertions.nim(*) raiseAssert +fatal.nim(*) sysFatal""" proc tmatch(x, p: string): bool = var i = 0 diff --git a/tests/errmsgs/t9768.nim b/tests/errmsgs/t9768.nim index 18588c87c..d369150a5 100644 --- a/tests/errmsgs/t9768.nim +++ b/tests/errmsgs/t9768.nim @@ -1,6 +1,6 @@ discard """ errmsg: "unhandled exception:" - file: "system.nim" + file: "system/fatal.nim" nimout: ''' stack trace: (most recent call last) t9768.nim(28, 33) main diff --git a/tests/manyloc/standalone/panicoverride.nim b/tests/manyloc/standalone/panicoverride.nim index 9d0d070c7..d9b3f4388 100644 --- a/tests/manyloc/standalone/panicoverride.nim +++ b/tests/manyloc/standalone/panicoverride.nim @@ -2,10 +2,6 @@ proc printf(frmt: cstring) {.varargs, importc, header: "<stdio.h>", cdecl.} proc exit(code: int) {.importc, header: "<stdlib.h>", cdecl.} -proc nimToCStringConv(s: NimString): cstring {.compilerProc, inline.} = - if s == nil or s.len == 0: result = cstring"" - else: result = cstring(addr s.data) - {.push stack_trace: off, profiler:off.} proc rawoutput(s: string) = |