我正在尝试用Nim语言编写一个用于调试打印的宏。
目前,此宏通过filename
将line
和instantiationInfo()
添加到输出中。
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__
?
答案 0 :(得分:6)
在运行时,您可以执行getFrame().procname
,但它仅适用于启用了堆栈跟踪(不适用于发布版本)。
在编译时令人惊讶的是,我找不到办法。宏模块中有callsite()
,但它还远远不够。这听起来像是适合macros.LineInfo
对象的东西。
一个hacky解决方案是使用__func__
并将其解析回Nim proc名称:
template procName: string =
var name: cstring
{.emit: "`name` = __func__;".}
($name).rsplit('_', 1)[0]
答案 1 :(得分:1)
以@ 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