summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md1
-rw-r--r--lib/pure/sugar.nim35
-rw-r--r--tests/stdlib/tsugar.nim12
3 files changed, 44 insertions, 4 deletions
diff --git a/changelog.md b/changelog.md
index 5f5222e59..b07186eed 100644
--- a/changelog.md
+++ b/changelog.md
@@ -104,6 +104,7 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior.
   `-d:nimLegacyParseQueryStrict`. `cgi.decodeData` which uses the same
   underlying code is also updated the same way.
 
+- Added `sugar.dumpToString` which improves on `sugar.dump`.
 
 
 
diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim
index 428136a4b..5e71ca54b 100644
--- a/lib/pure/sugar.nim
+++ b/lib/pure/sugar.nim
@@ -156,16 +156,45 @@ macro dump*(x: untyped): untyped =
   ## It accepts any expression and prints a textual representation
   ## of the tree representing the expression - as it would appear in
   ## source code - together with the value of the expression.
+  ##
+  ## See also: `dumpToString` which is more convenient and useful since
+  ## it expands intermediate templates/macros, returns a string instead of
+  ## calling `echo`, and works with statements and expressions.
   runnableExamples:
     let
       x = 10
       y = 20
-    dump(x + y) # will print `x + y = 30`
+    if false: dump(x + y) # if true would print `x + y = 30`
 
   let s = x.toStrLit
-  let r = quote do:
+  result = quote do:
     debugEcho `s`, " = ", `x`
-  return r
+
+macro dumpToStringImpl(s: static string, x: typed): string =
+  let s2 = x.toStrLit
+  if x.typeKind == ntyVoid:
+    result = quote do:
+      `s` & ": " & `s2`
+  else:
+    result = quote do:
+      `s` & ": " & `s2` & " = " & $`x`
+
+macro dumpToString*(x: untyped): string =
+  ## Returns the content of a statement or expression `x` after semantic analysis,
+  ## useful for debugging.
+  runnableExamples:
+    const a = 1
+    let x = 10
+    doAssert dumpToString(a + 2) == "a + 2: 3 = 3"
+    doAssert dumpToString(a + x) == "a + x: 1 + x = 11"
+    template square(x): untyped = x * x
+    doAssert dumpToString(square(x)) == "square(x): x * x = 100"
+    doAssert not compiles dumpToString(1 + nonexistant)
+    import std/strutils
+    doAssert "failedAssertImpl" in dumpToString(doAssert true) # example with a statement
+  result = newCall(bindSym"dumpToStringImpl")
+  result.add newLit repr(x)
+  result.add x
 
 # TODO: consider exporting this in macros.nim
 proc freshIdentNodes(ast: NimNode): NimNode =
diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim
index 2f79a9174..26b4eca1a 100644
--- a/tests/stdlib/tsugar.nim
+++ b/tests/stdlib/tsugar.nim
@@ -107,4 +107,14 @@ doAssert collect(for d in data.items: {d}) == data.toHashSet
 # bug #14332
 template foo =
   discard collect(newSeq, for i in 1..3: i)
-foo()
\ No newline at end of file
+foo()
+
+block: # dumpToString
+  template square(x): untyped = x * x
+  let x = 10
+  doAssert dumpToString(square(x)) == "square(x): x * x = 100"
+  let s = dumpToString(doAssert 1+1 == 2)
+  doAssert "failedAssertImpl" in s
+  let s2 = dumpToString:
+    doAssertRaises(AssertionDefect): doAssert false
+  doAssert "except AssertionDefect" in s2