diff options
Diffstat (limited to 'lib/std')
-rw-r--r-- | lib/std/assertions.nim | 121 | ||||
-rw-r--r-- | lib/std/enumutils.nim | 4 | ||||
-rw-r--r-- | lib/std/jsonutils.nim | 3 | ||||
-rw-r--r-- | lib/std/packedsets.nim | 3 | ||||
-rw-r--r-- | lib/std/private/globs.nim | 4 | ||||
-rw-r--r-- | lib/std/sha1.nim | 3 |
6 files changed, 138 insertions, 0 deletions
diff --git a/lib/std/assertions.nim b/lib/std/assertions.nim new file mode 100644 index 000000000..3d2112b1a --- /dev/null +++ b/lib/std/assertions.nim @@ -0,0 +1,121 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2022 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements assertion handling. + +when not declared(sysFatal): + include "system/fatal" + +import std/private/miscdollars +# --------------------------------------------------------------------------- +# helpers + +type InstantiationInfo = tuple[filename: string, line: int, column: int] + +proc `$`(info: InstantiationInfo): string = + # The +1 is needed here + # instead of overriding `$` (and changing its meaning), consider explicit name. + result = "" + result.toLocation(info.filename, info.line, info.column + 1) + +# --------------------------------------------------------------------------- + +when not defined(nimHasSinkInference): + {.pragma: nosinks.} + +proc raiseAssert*(msg: string) {.noinline, noreturn, nosinks.} = + ## Raises an `AssertionDefect` with `msg`. + sysFatal(AssertionDefect, msg) + +proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = + ## Raises an `AssertionDefect` with `msg`, but this is hidden + ## from the effect system. Called when an assertion failed. + # trick the compiler to not list `AssertionDefect` when called + # by `assert`. + # xxx simplify this pending bootstrap >= 1.4.0, after which cast not needed + # anymore since `Defect` can't be raised. + type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, tags: [].} + cast[Hide](raiseAssert)(msg) + +template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool]) = + when enabled: + const + loc = instantiationInfo(fullPaths = compileOption("excessiveStackTrace")) + ploc = $loc + bind instantiationInfo + mixin failedAssertImpl + {.line: loc.}: + if not cond: + failedAssertImpl(ploc & " `" & expr & "` " & msg) + +template assert*(cond: untyped, msg = "") = + ## Raises `AssertionDefect` with `msg` if `cond` is false. Note + ## that `AssertionDefect` is hidden from the effect system, so it doesn't + ## produce `{.raises: [AssertionDefect].}`. This exception is only supposed + ## to be caught by unit testing frameworks. + ## + ## No code will be generated for `assert` when passing `-d:danger` (implied by `--assertions:off`). + ## See `command line switches <nimc.html#compiler-usage-commandminusline-switches>`_. + runnableExamples: assert 1 == 1 + runnableExamples("--assertions:off"): + assert 1 == 2 # no code generated, no failure here + runnableExamples("-d:danger"): assert 1 == 2 # ditto + assertImpl(cond, msg, astToStr(cond), compileOption("assertions")) + +template doAssert*(cond: untyped, msg = "") = + ## Similar to `assert <#assert.t,untyped,string>`_ but is always turned on regardless of `--assertions`. + runnableExamples: + doAssert 1 == 1 # generates code even when built with `-d:danger` or `--assertions:off` + assertImpl(cond, msg, astToStr(cond), true) + +template onFailedAssert*(msg, code: untyped): untyped {.dirty.} = + ## Sets an assertion failure handler that will intercept any assert + ## statements following `onFailedAssert` in the current scope. + runnableExamples: + type MyError = object of CatchableError + lineinfo: tuple[filename: string, line: int, column: int] + # block-wide policy to change the failed assert exception type in order to + # include a lineinfo + onFailedAssert(msg): + raise (ref MyError)(msg: msg, lineinfo: instantiationInfo(-2)) + doAssertRaises(MyError): doAssert false + template failedAssertImpl(msgIMPL: string): untyped {.dirty.} = + let msg = msgIMPL + code + +template doAssertRaises*(exception: typedesc, code: untyped) = + ## Raises `AssertionDefect` if specified `code` does not raise `exception`. + runnableExamples: + doAssertRaises(ValueError): raise newException(ValueError, "Hello World") + doAssertRaises(CatchableError): raise newException(ValueError, "Hello World") + doAssertRaises(AssertionDefect): doAssert false + var wrong = false + const begin = "expected raising '" & astToStr(exception) & "', instead" + const msgEnd = " by: " & astToStr(code) + template raisedForeign = raiseAssert(begin & " raised foreign exception" & msgEnd) + when Exception is exception: + try: + if true: + code + wrong = true + except Exception as e: discard + except: raisedForeign() + else: + try: + if true: + code + wrong = true + except exception: + discard + except Exception as e: + mixin `$` # alternatively, we could define $cstring in this module + raiseAssert(begin & " raised '" & $e.name & "'" & msgEnd) + except: raisedForeign() + if wrong: + raiseAssert(begin & " nothing was raised" & msgEnd) diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim index b7d2b9f89..9d4ff1bcf 100644 --- a/lib/std/enumutils.nim +++ b/lib/std/enumutils.nim @@ -10,6 +10,10 @@ import macros from typetraits import OrdinalEnum, HoleyEnum +when defined(nimPreviewSlimSystem): + import std/assertions + + # xxx `genEnumCaseStmt` needs tests and runnableExamples macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 19384b5d1..722ea49b5 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -34,6 +34,9 @@ import macros from enumutils import symbolName from typetraits import OrdinalEnum +when defined(nimPreviewSlimSystem): + import std/assertions + when not defined(nimFixedForwardGeneric): # xxx remove pending csources_v1 update >= 1.2.0 proc to[T](node: JsonNode, t: typedesc[T]): T = diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim index b2ee917eb..1e2892658 100644 --- a/lib/std/packedsets.nim +++ b/lib/std/packedsets.nim @@ -24,6 +24,9 @@ import std/private/since import hashes +when defined(nimPreviewSlimSystem): + import std/assertions + type BitScalar = uint diff --git a/lib/std/private/globs.nim b/lib/std/private/globs.nim index 190316f93..28a810372 100644 --- a/lib/std/private/globs.nim +++ b/lib/std/private/globs.nim @@ -8,6 +8,10 @@ import os when defined(windows): from strutils import replace +when defined(nimPreviewSlimSystem): + import std/assertions + + when defined(nimHasEffectsOf): {.experimental: "strictEffects".} else: diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim index ed962707b..50175024c 100644 --- a/lib/std/sha1.nim +++ b/lib/std/sha1.nim @@ -29,6 +29,9 @@ runnableExamples("-r:off"): import strutils from endians import bigEndian32, bigEndian64 +when defined(nimPreviewSlimSystem): + import std/syncio + const Sha1DigestSize = 20 type |