我怎样才能在 Nim 中获得过程的名称?
How can I get the name of procedure in Nim?
我正在尝试用 Nim 语言编写用于调试打印的宏。
目前此宏通过 instantiationInfo()
.
将 filename
和 line
添加到输出中
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
我正在尝试用 Nim 语言编写用于调试打印的宏。
目前此宏通过 instantiationInfo()
.
filename
和 line
添加到输出中
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