我怎样才能在 Nim 中获得过程的名称?

How can I get the name of procedure in Nim?

我正在尝试用 Nim 语言编写用于调试打印的宏。 目前此宏通过 instantiationInfo().

filenameline 添加到输出中
import macros  
macro debugPrint(msg: untyped): typed =
  result = quote do:
    let pos = instantiationInfo()
    echo pos.filename, ":", pos.line, ": ", `msg`

proc hello() =
  debugPrint "foo bar"
hello()

当前输出:

debug_print.nim:9: foo bar

我想添加调用宏的地方的过程(或迭代器)的名称。

期望的输出:

debug_print.nim:9(proc hello): foo bar

如何在 Nim 中获取过程(或迭代器)的名称,就像在 C 中的 __func__

在运行时你可以做 getFrame().procname,但它只适用于启用堆栈跟踪(不适用于发布版本)。

令人惊讶的是,在编译时我无法找到实现它的方法。宏模块中有 callsite(),但还不够。这听起来像是适合 macros.LineInfo 对象的东西。

一个 hacky 的解决方案是也使用 __func__ 并将其解析回 Nim proc 名称:

template procName: string =
  var name: cstring
  {.emit: "`name` = __func__;".}
  ($name).rsplit('_', 1)[0]

建立在@def- 的回答之上,但使其更健壮地处理包含下划线的函数的边缘情况,以及包含或不包含尾随 _N 的散列 还使用更多唯一名称,否则如果 proc 定义变量 name

,宏将失败
import strutils

proc procNameAux*(name:cstring): string =
  let temp=($name).rsplit('_', 2)
    #CHECKME: IMPROVE; the magic '4' chosen to be enough for most cases
    # EG: bar_baz_9c8JPzPvtM9azO6OB23bjc3Q_3
  if temp.len>=3 and temp[2].len < 4:
    ($name).rsplit('_', 2)[0]
  else:
    # EG: foo_9c8JPzPvtM9azO6OB23bjc3Q
    ($name).rsplit('_', 1)[0]

template procName*: string =
  var name2: cstring
  {.emit: "`name2` = __func__;".}
  procNameAux(name2)

proc foo_bar()=
  echo procName # prints foo_bar

foo_bar()

注意:这仍然有一些问题会在复杂的边缘情况下触发,请参阅 https://github.com/nim-lang/Nim/issues/8212