Tcl:Is 有办法显示 tcl 中的哪一行抛出错误吗?

Tcl:Is there a way to show which line in tcl throw an error?

当我获取一个tcl文件时,当运行一个未知命令时会报错。

Tcl> source run.tcl
$inside tcl file$$> setup_desgin
    Design setup...
    Done
$inside tcl file$$> my_prove
    Info: proving started
    Info: ....
    Info: ....
$inside tcl file$$> ::unknown my_pro
    invalid command name "my_pro"

有没有办法在tcl文件中显示错误行的行号,如下所示?

Tcl> source run.tcl
$inside tcl file$$> setup_desgin
    Design setup...
    Done
$inside tcl file$$> my_prove
    Info: proving started
    Info: ....
    Info: ....
$inside tcl file$$> ::unknown my_pro
    invalid command name "my_pro" (run.tcl:5)

我们想要这个,因为我们可能有一个非常大的 run.tcl 和 minions of line。

可以在里面重新定义unknown command and use the info frame命令来获取位置。类似于:

# Save the default unknown if you want
rename ::unknown ::original_unknown

proc ::unknown {name args} {
    set caller [info frame -1]
    dict with caller {
        switch $type {
            source {
                puts stderr "invalid command name \"$name\" (in file $file:$line)"
            }
            proc {
                if {[info exists lambda]} {
                    puts stderr "invalid command name \"$name\" (in lambda $lambda:$line)"
                } else {
                    puts stderr "invalid command name \"$name\" (in proc $proc:$line)"
                }
            }
            eval {
                puts stderr "invalid command name \"$name\" (in eval {$cmd}:$line)"
            }
            precompiled {
                puts stderr "Invalid command name \"$name\""
            }
        }
    }
}

用法示例:

% source my_unknown.tcl
% source bad.tcl
invalid command name "put" (in file /home/shawn/src/bad.tcl:3)

一般情况下获取这些信息实际上是相当困难的。准确的行号信息目前只有当代码在执行堆栈上时才可用。幸运的是,您可以通过 leave-step 跟踪找出发生了什么(拦截 unknown 仅适用于未知命令;跟踪可以捕获 所有 错误)。在下面的代码中,我把它放在 eval 上,但在一个更实际的例子中,你会把它放在 source 或类似的东西上。

set errorlineSet 0
proc LEAVESTEP {cmd code result op args} {
    global errorline errorlineSet
    if {$code == 1} {
        if {!$errorlineSet} {
            set errorline [dict get [info frame -4] line]
        }
        set errorlineSet 1
    } else {
        set errorlineSet 0
    }
}

try {
    trace add execution eval leavestep LEAVESTEP
    eval {
        sdfgsldfjg;   # This is line 17
    }
} on error {msg opt} {
    puts "ERROR: $msg (line: $errorline) (local line: [dict get $opt -errorline])"
} finally {
    trace remove execution eval leavestep LEAVESTEP
}

当我将所有这些保存到一个文件并运行它时,它会打印出:

ERROR: invalid command name "sdfgsldfjg" (line: 17) (local line: 3)

如您所见,结果选项字典中也有 -errorline 键,但在本例中它映射到 3,这是相当误导的!它使用该值是因为向后兼容,但我不相信它是否有用。