diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index 77f7c844f3..03d5c95eb3 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -23,7 +23,7 @@ proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string = else: var buf: array[0..80, char] c_sprintf(buf, "%#.16e" & literalPostfix, f) - result = $buf + result = newString(buf) proc encodeStr*(s: string, result: var string) = for i in countup(0, len(s) - 1): @@ -133,4 +133,3 @@ iterator decodeStrArray*(s: cstring): string = while s[i] != '\0': yield decodeStr(s, i) if s[i] == ' ': inc i - diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 2195f6327e..5211bc00c8 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1010,7 +1010,7 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: while true: var x = readdir(d) if x == nil: break - var y = $x.d_name + var y = newString(x.d_name) if y != "." and y != "..": var s: Stat if not relative: diff --git a/lib/system.nim b/lib/system.nim index d62c0424eb..3dc892c442 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1852,7 +1852,7 @@ proc `$` *(x: float): string {.magic: "FloatToStr", noSideEffect.} proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.} ## The stringify operator for a boolean argument. Returns `x` ## converted to the string "false" or "true". - +# proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.} ## The stringify operator for a character argument. Returns `x` ## converted to a string. @@ -1872,6 +1872,27 @@ proc `$` *[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.} ## a ``$`` operator for a concrete enumeration is provided, this is ## used instead. (In other words: *Overwriting* is possible.) +proc `$`*[T: ref](arg: T): string = + ## The stringify operator to handle the nil value of all ref types. + ## Then it forwards to stringify operator of the underlying (value) type. + if arg.isNil: + "nil" + else: + "ref " & $arg[] + +proc `$`*[T: ptr](arg: T): string = + ## The stringify operator to handle the nil value of all ptr types. + ## Then it forwards to stringify operator of the underlying (value) type. + if arg.isNil: + "nil" + else: + "ptr " & $arg[] + +proc newString*[N](data: array[N, char]): string = + ## Construct a string from an array of characters. The `data` is + ## expected to be a null terminated string as it is often used in C. + $(cast[cstring](data[0].unsafeAddr)) + # undocumented: proc getRefcount*[T](x: ref T): int {.importc: "getRefcount", noSideEffect.} proc getRefcount*(x: string): int {.importc: "getRefcount", noSideEffect.} @@ -2410,20 +2431,25 @@ proc `$`*[T: tuple|object](x: T): string = result.add("...") result.add(")") -proc collectionToString[T: set | seq](x: T, b, e: string): string = - when x is seq: - if x.isNil: return "nil" - result = b +proc collectionToString[T](x: T, prefix, separator, suffix: string): string = + result = prefix var firstElement = true for value in items(x): - if not firstElement: result.add(", ") + if firstElement: + firstElement = false + else: + result.add(separator) + when compiles(value.isNil): - if value.isNil: result.add "nil" - else: result.add($value) + # this branch should not be necessary + if value.isNil: + result.add "nil" + else: + result.add($value) else: result.add($value) - firstElement = false - result.add(e) + + result.add(suffix) proc `$`*[T](x: set[T]): string = ## generic ``$`` operator for sets that is lifted from the components @@ -2431,7 +2457,7 @@ proc `$`*[T](x: set[T]): string = ## ## .. code-block:: nim ## ${23, 45} == "{23, 45}" - collectionToString(x, "{", "}") + collectionToString(x, "{", ", ", "}") proc `$`*[T](x: seq[T]): string = ## generic ``$`` operator for seqs that is lifted from the components @@ -2439,13 +2465,10 @@ proc `$`*[T](x: seq[T]): string = ## ## .. code-block:: nim ## $(@[23, 45]) == "@[23, 45]" - collectionToString(x, "@[", "]") - -when false: - # causes bootstrapping to fail as we use array of chars and cstring should - # match better ... - proc `$`*[T, IDX](x: array[IDX, T]): string = - collectionToString(x, "[", "]") + if x.isNil: + "nil" + else: + collectionToString(x, "@[", ", ", "]") # ----------------- GC interface --------------------------------------------- @@ -3301,6 +3324,11 @@ elif defined(JS): include "system/sysio" +proc `$`*[T, IDX](x: array[IDX, T]): string = + ## generic ``$`` operator for arrays that is lifted from the components + collectionToString(x, "[", ", ", "]") + + proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} = ## a shorthand for ``echo(errormsg); quit(errorcode)``. echo(errormsg) diff --git a/lib/system/repr.nim b/lib/system/repr.nim index ab02c58a2a..fcf65dd0e3 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -18,7 +18,7 @@ proc reprFloat(x: float): string {.compilerproc.} = return $x proc reprPointer(x: pointer): string {.compilerproc.} = var buf: array[0..59, char] discard c_sprintf(buf, "%p", x) - return $buf + return newString(buf) proc `$`(x: uint64): string = if x == 0: @@ -36,7 +36,7 @@ proc `$`(x: uint64): string = let half = i div 2 # Reverse for t in 0 .. < half: swap(buf[t], buf[i-t-1]) - result = $buf + result = newString(buf) proc reprStrAux(result: var string, s: cstring; len: int) = if cast[pointer](s) == nil: diff --git a/tests/system/toString.nim b/tests/system/toString.nim index a2337f5dd4..f9697ec759 100644 --- a/tests/system/toString.nim +++ b/tests/system/toString.nim @@ -12,14 +12,16 @@ inf -inf nan nil -nil''' +nil +(a: 0, b: nil) +nil +ptr (a: 0, b: nil)''' """ echo($(@[23, 45])) echo($(@["", "foo", "bar"])) #echo($(["", "foo", "bar"])) #echo($([23, 45])) - # bug #2395 let alphaSet: set[char] = {'a'..'c'} @@ -40,3 +42,30 @@ var x: seq[string] var y: string echo(x) echo(y) + +type + Foo = object + a: int + b: string + +var foo1: Foo +var foo2: ref Foo +var foo3: ptr Foo = foo1.addr + +echo foo1 +echo foo2 +echo foo3 + +const + data = @['a','b', '\0', 'c','d'] + dataStr = $data + +# ensure same result when on VM or when at program execution +doAssert dataStr == $data + +import strutils +# array test +let arr = ['H','e','l','l','o',' ','W','o','r','l','d','!','\0'] + +doAssert startsWith($arr, "[H, e, l, l, o, , W, o, r, l, d, !,") +doAssert newString(arr) == "Hello World!"