summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/debugutils.nim37
-rw-r--r--compiler/options.nim3
-rw-r--r--compiler/semexprs.nim7
-rw-r--r--tests/compiler/tdebugutils.nim38
4 files changed, 85 insertions, 0 deletions
diff --git a/compiler/debugutils.nim b/compiler/debugutils.nim
index 235c100b3..d109d2121 100644
--- a/compiler/debugutils.nim
+++ b/compiler/debugutils.nim
@@ -4,7 +4,26 @@ Utilities to help with debugging nim compiler.
 Experimental API, subject to change.
 ]##
 
+#[
+## example
+useful debugging flags:
+--stacktrace -d:debug -d:nimDebugUtils
+ nim c -o:bin/nim_temp --stacktrace -d:debug -d:nimDebugUtils compiler/nim
+
+## future work
+* expose and improve astalgo.debug, replacing it by std/prettyprints,
+  refs https://github.com/nim-lang/RFCs/issues/385
+]#
+
 import options
+import std/wrapnils
+export wrapnils
+  # allows using things like: `?.n.sym.typ.len`
+
+import std/stackframes
+export stackframes
+  # allows using things like: `setFrameMsg c.config$n.info & " " & $n.kind`
+  # which doesn't log, but augments stacktrace with side channel information
 
 var conf0: ConfigRef
 
@@ -17,3 +36,21 @@ proc onNewConfigRef*(conf: ConfigRef) {.inline.} =
 proc getConfigRef*(): ConfigRef =
   ## nil, if -d:nimDebugUtils wasn't specified
   result = conf0
+
+proc isCompilerDebug*(): bool =
+  ##[
+  Provides a simple way for user code to enable/disable logging in the compiler
+  in a granular way. This can then be used in the compiler as follows:
+  ```nim
+  if isCompilerDebug():
+    echo ?.n.sym.typ.len
+  ```
+  ]##
+  runnableExamples:
+    proc main =
+      echo 2
+      {.define(nimCompilerDebug).}
+      echo 3.5 # code section in which `isCompilerDebug` will be true
+      {.undef(nimCompilerDebug).}
+      echo 'x'
+  conf0.isDefined("nimCompilerDebug")
diff --git a/compiler/options.nim b/compiler/options.nim
index 1851770d9..05d8ee5b7 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -472,7 +472,10 @@ const foreignPackageNotesDefault* = {
 proc isDefined*(conf: ConfigRef; symbol: string): bool
 
 when defined(nimDebugUtils):
+  # this allows inserting debugging utilties in all modules that import `options`
+  # with a single switch, which is useful when debugging compiler.
   import debugutils
+  export debugutils
 
 proc initConfigRefCommon(conf: ConfigRef) =
   conf.selectedGC = gcRefc
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 53a5f149e..c885f4963 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -2716,6 +2716,13 @@ proc getNilType(c: PContext): PType =
 proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   when defined(nimCompilerStacktraceHints):
     setFrameMsg c.config$n.info & " " & $n.kind
+  when false: # see `tdebugutils`
+    if isCompilerDebug():
+      echo (">", c.config$n.info, n, flags, n.kind)
+    defer:
+      if isCompilerDebug():
+        echo ("<", c.config$n.info, n, ?.result.typ)
+
   result = n
   if c.config.cmd == cmdIdeTools: suggestExpr(c, n)
   if nfSem in n.flags: return
diff --git a/tests/compiler/tdebugutils.nim b/tests/compiler/tdebugutils.nim
new file mode 100644
index 000000000..50b15cb78
--- /dev/null
+++ b/tests/compiler/tdebugutils.nim
@@ -0,0 +1,38 @@
+discard """
+  joinable: false
+  disabled: true
+"""
+
+#[
+This test illustrates some features of `debugutils` to debug the compiler.
+
+## example
+this shows how to enable compiler logging just for a section of user code,
+without generating tons of unrelated log messages for code you're not interested
+in debugging.
+
+```sh
+# enable some debugging code, e.g. the `when false:` block in `semExpr`
+nim c -o:bin/nim_temp --stacktrace -d:debug -d:nimDebugUtils compiler/nim
+bin/nim_temp c tests/compiler/tdebugutils.nim
+```
+
+(use --filenames:abs for abs files)
+
+## result
+("<", "tdebugutils.nim(16, 3)",  {.define(nimCompilerDebug).}, nil)
+(">", "tdebugutils.nim(17, 3)", let a = 2.5 * 3, {}, nkLetSection)
+(">", "tdebugutils.nim(17, 15)", 2.5 * 3, {efAllowDestructor, efWantValue}, nkInfix)
+(">", "tdebugutils.nim(17, 11)", 2.5, {efAllowStmt, efDetermineType, efOperand}, nkFloatLit)
+("<", "tdebugutils.nim(17, 11)", 2.5, float64)
+(">", "tdebugutils.nim(17, 17)", 3, {efAllowStmt, efDetermineType, efOperand}, nkIntLit)
+("<", "tdebugutils.nim(17, 17)", 3, int literal(3))
+("<", "tdebugutils.nim(17, 15)", 2.5 * 3, float)
+("<", "tdebugutils.nim(17, 3)", let a = 2.5 * 3, nil)
+(">", "tdebugutils.nim(18, 3)",  {.undef(nimCompilerDebug).}, {}, nkPragma)
+]#
+
+proc main =
+  {.define(nimCompilerDebug).}
+  let a = 2.5 * 3
+  {.undef(nimCompilerDebug).}