diff --git a/compiler/ast.nim b/compiler/ast.nim index 27e4fab63374b..0decbc935864f 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -744,6 +744,9 @@ type module*: int32 item*: int32 +proc `$`*(x: ItemId): string = + "(module: " & $x.module & ", item: " & $x.item & ")" + proc `==`*(a, b: ItemId): bool {.inline.} = a.item == b.item and a.module == b.module diff --git a/compiler/passaux.nim b/compiler/passaux.nim index 68b7832489bb0..af507d2108768 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -22,6 +22,8 @@ proc verboseOpen(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext # xxx consider either removing this or keeping for documentation for how to add a pass result = VerboseRef(config: graph.config, idgen: idgen) +import std/objectdollar + proc verboseProcess(context: PPassContext, n: PNode): PNode = # called from `process` in `processTopLevelStmt`. result = n diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 4782f0a7381d4..e91b99c3a3ef9 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -11,6 +11,9 @@ import os, tables, strutils, times, heapqueue, options, deques, cstrutils import system/stacktraces +when defined(nimPreviewSlimSystem): + import std/objectdollar # for StackTraceEntry + # TODO: This shouldn't need to be included, but should ideally be exported. type CallbackFunc = proc () {.closure, gcsafe.} diff --git a/lib/std/objectdollar.nim b/lib/std/objectdollar.nim new file mode 100644 index 0000000000000..f413bbc46637f --- /dev/null +++ b/lib/std/objectdollar.nim @@ -0,0 +1,11 @@ +import std/private/miscdollars + +proc `$`*[T: object](x: T): string = + ## Generic `$` operator for objects with similar output to + ## `$` for named tuples. + runnableExamples: + type Foo = object + a, b: int + let x = Foo(a: 23, b: 45) + assert $x == "(a: 23, b: 45)" + tupleObjectDollar(result, x) diff --git a/lib/std/private/miscdollars.nim b/lib/std/private/miscdollars.nim index 840fedf54e626..47b788ee946f4 100644 --- a/lib/std/private/miscdollars.nim +++ b/lib/std/private/miscdollars.nim @@ -12,3 +12,42 @@ template toLocation*(result: var string, file: string | cstring, line: int, col: result.add ", " addInt(result, col) result.add ")" + +when defined(nimHasIsNamedTuple): + proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} +else: + # for bootstrap; remove after release 1.2 + proc isNamedTuple(T: typedesc): bool = + # Taken from typetraits. + when T isnot tuple: result = false + else: + var t: T + for name, _ in t.fieldPairs: + when name == "Field0": + return compiles(t.Field0) + else: + return true + return false + +template tupleObjectDollar*[T: tuple | object](result: var string, x: T) = + result = "(" + const isNamed = T is object or isNamedTuple(typeof(T)) + var count {.used.} = 0 + for name, value in fieldPairs(x): + if count > 0: result.add(", ") + when isNamed: + result.add(name) + result.add(": ") + count.inc + when compiles($value): + when value isnot string and value isnot seq and compiles(value.isNil): + if value.isNil: result.add "nil" + else: result.addQuoted(value) + else: + result.addQuoted(value) + else: + result.add("...") + when not isNamed: + if count == 1: + result.add(",") # $(1,) should print as the semantically legal (1,) + result.add(")") diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index 46085d2aa688d..b060aedb0de98 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -3,7 +3,7 @@ runnableExamples: assert $0.1 == "0.1" assert $(-2*3) == "-6" -import std/private/digitsutils +import std/private/[digitsutils, miscdollars] import system/formatfloat export addFloat @@ -69,24 +69,7 @@ proc `$`*(t: typedesc): string {.magic: "TypeTrait".} ## doAssert $(typeof("Foo")) == "string" ## static: doAssert $(typeof(@['A', 'B'])) == "seq[char]" -when defined(nimHasIsNamedTuple): - proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} -else: - # for bootstrap; remove after release 1.2 - proc isNamedTuple(T: typedesc): bool = - # Taken from typetraits. - when T isnot tuple: result = false - else: - var t: T - for name, _ in t.fieldPairs: - when name == "Field0": - return compiles(t.Field0) - else: - return true - return false - - -proc `$`*[T: tuple|object](x: T): string = +proc `$`*[T: tuple](x: T): string = ## Generic `$` operator for tuples that is lifted from the components ## of `x`. Example: ## @@ -94,28 +77,11 @@ proc `$`*[T: tuple|object](x: T): string = ## $(23, 45) == "(23, 45)" ## $(a: 23, b: 45) == "(a: 23, b: 45)" ## $() == "()" - result = "(" - const isNamed = T is object or isNamedTuple(T) - var count {.used.} = 0 - for name, value in fieldPairs(x): - if count > 0: result.add(", ") - when isNamed: - result.add(name) - result.add(": ") - count.inc - when compiles($value): - when value isnot string and value isnot seq and compiles(value.isNil): - if value.isNil: result.add "nil" - else: result.addQuoted(value) - else: - result.addQuoted(value) - else: - result.add("...") - when not isNamed: - if count == 1: - result.add(",") # $(1,) should print as the semantically legal (1,) - result.add(")") + tupleObjectDollar(result, x) +when not defined(nimPreviewSlimSystem): + import std/objectdollar + export objectdollar proc collectionToString[T](x: T, prefix, separator, suffix: string): string = result = prefix diff --git a/tests/stdlib/tobjectdollar.nim b/tests/stdlib/tobjectdollar.nim new file mode 100644 index 0000000000000..cf78fa255af7c --- /dev/null +++ b/tests/stdlib/tobjectdollar.nim @@ -0,0 +1,14 @@ +discard """ + matrix: "-d:nimPreviewSlimSystem" +""" + +import std/assertions + +type Foo = object + a, b: int + +let x = Foo(a: 23, b: 45) +doAssert not compiles($x) +import std/objectdollar +doAssert compiles($x) +doAssert $x == "(a: 23, b: 45)" diff --git a/tests/stdlib/toptions.nim b/tests/stdlib/toptions.nim index 71c52a07e49aa..633be6c045290 100644 --- a/tests/stdlib/toptions.nim +++ b/tests/stdlib/toptions.nim @@ -4,6 +4,9 @@ discard """ import std/[json, options] +when defined(nimPreviewSlimSystem): + import std/objectdollar + # RefPerson is used to test that overloaded `==` operator is not called by # options. It is defined here in the global scope, because otherwise the test diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim index 1863d313881f5..ea7be8297eae7 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -3,6 +3,9 @@ import genericstrformat import std/[strformat, strutils, times, tables, json] +when defined(nimPreviewSlimSystem): + import std/objectdollar + proc main() = block: # issue #7632 doAssert works(5) == "formatted 5"