diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index 77f7c844f3..6e77e6b8f9 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -10,7 +10,7 @@ ## Serialization utilities for the compiler. import strutils -proc c_sprintf(buf, frmt: cstring) {.importc: "sprintf", header: "", nodecl, varargs.} +proc c_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf", header: "", nodecl, varargs.} proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string = if f != f: @@ -22,8 +22,8 @@ proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string = else: result = "-INF" else: var buf: array[0..80, char] - c_sprintf(buf, "%#.16e" & literalPostfix, f) - result = $buf + discard c_snprintf(buf.cstring, buf.len.uint, "%#.16e%s", f, literalPostfix.cstring) + result = $buf.cstring 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/nativesockets.nim b/lib/pure/nativesockets.nim index 98fc62a3b9..c8fb041d80 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -500,7 +500,7 @@ proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = if inet_ntop(name.sin6_family.cint, addr name.sin6_addr, buf.cstring, sizeof(buf).int32).isNil: raiseOSError(osLastError()) - result = ($buf, Port(nativesockets.ntohs(name.sin6_port))) + result = ($buf.cstring, Port(nativesockets.ntohs(name.sin6_port))) else: raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") @@ -536,7 +536,7 @@ proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) = if inet_ntop(name.sin6_family.cint, addr name.sin6_addr, buf.cstring, sizeof(buf).int32).isNil: raiseOSError(osLastError()) - result = ($buf, Port(nativesockets.ntohs(name.sin6_port))) + result = ($buf.cstring, Port(nativesockets.ntohs(name.sin6_port))) else: raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") diff --git a/lib/pure/os.nim b/lib/pure/os.nim index b85181edf3..e6ef96ba3b 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -790,7 +790,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 = $x.d_name.cstring if y != "." and y != "..": var s: Stat if not relative: diff --git a/lib/system.nim b/lib/system.nim index 207d616d2c..d19a406cb8 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1875,7 +1875,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. @@ -2437,20 +2437,28 @@ 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) + # prevent temporary string allocation + elif compiles(result.add(value)): + 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 @@ -2458,7 +2466,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 @@ -2466,13 +2474,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 --------------------------------------------- @@ -3329,6 +3334,10 @@ 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..58c86b0dbe 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -16,27 +16,27 @@ proc reprInt(x: int64): string {.compilerproc.} = return $x 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 + var buf: array[60, char] + discard c_sprintf(buf.cstring, "%p", x) + result = $buf.cstring proc `$`(x: uint64): string = if x == 0: result = "0" else: - var buf: array[60, char] + result = newString(60) var i = 0 var n = x while n != 0: let nn = n div 10'u64 - buf[i] = char(n - 10'u64 * nn + ord('0')) + result[i] = char(n - 10'u64 * nn + ord('0')) inc i n = nn + result.setLen i let half = i div 2 # Reverse - for t in 0 .. < half: swap(buf[t], buf[i-t-1]) - result = $buf + for t in 0 .. < half: swap(result[t], result[i-t-1]) proc reprStrAux(result: var string, s: cstring; len: int) = if cast[pointer](s) == nil: diff --git a/tests/async/tnewasyncudp.nim b/tests/async/tnewasyncudp.nim index bf54c0d06a..da731f4b86 100644 --- a/tests/async/tnewasyncudp.nim +++ b/tests/async/tnewasyncudp.nim @@ -54,7 +54,7 @@ proc launchSwarm(name: ptr SockAddr) {.async.} = k = 0 while k < messagesToSend: zeroMem(addr(buffer[0]), 16384) - zeroMem(cast[pointer](addr(saddr)), sizeof(Sockaddr_in)) + zeroMem(cast[pointer](addr(saddr)), sizeof(Sockaddr_in)) var message = "Message " & $(i * messagesToSend + k) await sendTo(sock, addr message[0], len(message), name, sizeof(Sockaddr_in).SockLen) @@ -62,7 +62,7 @@ proc launchSwarm(name: ptr SockAddr) {.async.} = 16384, cast[ptr SockAddr](addr saddr), addr slen) size = 0 - var grammString = $buffer + var grammString = $buffer.cstring if grammString == message: saveSendingPort(sockport) inc(recvCount) @@ -84,7 +84,7 @@ proc readMessages(server: AsyncFD) {.async.} = 16384, cast[ptr SockAddr](addr(saddr)), addr(slen)) size = 0 - var grammString = $buffer + var grammString = $buffer.cstring if grammString.startswith("Message ") and saddr.sin_addr.s_addr == 0x100007F: await sendTo(server, addr grammString[0], len(grammString), diff --git a/tests/gc/gctest.nim b/tests/gc/gctest.nim index b3b9af6080..f5c81f033a 100644 --- a/tests/gc/gctest.nim +++ b/tests/gc/gctest.nim @@ -31,7 +31,7 @@ type of nkList: sons: seq[PCaseNode] else: unused: seq[string] - TIdObj* = object of TObject + TIdObj* = object of RootObj id*: int # unique id; use this for comparisons and not the pointers PIdObj* = ref TIdObj diff --git a/tests/misc/treadx.nim b/tests/misc/treadx.nim index 49b6ad6912..2e3904cd12 100644 --- a/tests/misc/treadx.nim +++ b/tests/misc/treadx.nim @@ -6,9 +6,8 @@ when not defined(windows): var buf: array[0..10, char] while true: var r = read(0, addr(buf), sizeof(buf)-1) - add inp, $buf + add inp, $buf.cstring if r != sizeof(buf)-1: break echo inp #dafkladskölklödsaf ölksdakölfölksfklwe4iojr389wr 89uweokf sdlkf jweklr jweflksdj fioewjfsdlfsd - diff --git a/tests/system/toString.nim b/tests/system/toString.nim index a2337f5dd4..bc8720b554 100644 --- a/tests/system/toString.nim +++ b/tests/system/toString.nim @@ -1,42 +1,53 @@ discard """ - output:'''@[23, 45] -@[, foo, bar] -{a, b, c} -2.3242 -2.982 -123912.1 -123912.1823 -5.0 -1e+100 -inf --inf -nan -nil -nil''' + output:"" """ -echo($(@[23, 45])) -echo($(@["", "foo", "bar"])) -#echo($(["", "foo", "bar"])) -#echo($([23, 45])) +doAssert "@[23, 45]" == $(@[23, 45]) +doAssert "[32, 45]" == $([32, 45]) +doAssert "@[, foo, bar]" == $(@["", "foo", "bar"]) +doAssert "[, foo, bar]" == $(["", "foo", "bar"]) # bug #2395 - let alphaSet: set[char] = {'a'..'c'} -echo alphaSet - -echo($(2.3242)) -echo($(2.982)) -echo($(123912.1)) -echo($(123912.1823)) -echo($(5.0)) -echo($(1e100)) -echo($(1e1000000)) -echo($(-1e1000000)) -echo($(0.0/0.0)) +doAssert "{a, b, c}" == $alphaSet +doAssert "2.3242" == $(2.3242) +doAssert "2.982" == $(2.982) +doAssert "123912.1" == $(123912.1) +doAssert "123912.1823" == $(123912.1823) +doAssert "5.0" == $(5.0) +doAssert "1e+100" == $(1e100) +doAssert "inf" == $(1e1000000) +doAssert "-inf" == $(-1e1000000) +doAssert "nan" == $(0.0/0.0) # nil tests +# maybe a bit inconsistent in types var x: seq[string] -var y: string -echo(x) -echo(y) +doAssert "nil" == $(x) + +var y: string = nil +doAssert nil == $(y) + +type + Foo = object + a: int + b: string + +var foo1: Foo + +# nil string should be an some point in time equal to the empty string +doAssert(($foo1)[0..9] == "(a: 0, b: ") + +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 $arr == "[H, e, l, l, o, , W, o, r, l, d, !, \0]" +doAssert $arr.cstring == "Hello World!"