Since 8.6 and TIP #348, we now have the built-in info errorstack providing the same functionality more efficiently and robustly. The script-level emulation below is only for the curious, or for pre-8.6 releases.
if {[catch {some code} err]} {
Log "Argh: err\n$::errorInfo"
}or if you're catching from bgerror:
proc bgerror err {
Log "Argh: err\n$::errorInfo"
}set ::errorLevel -1
set ::errorStack {}
trace add variable ::errorInfo write {
set __n [info level]
if {($__n>0)&&($__n!=$::errorLevel)} {
set ::errorLevel $__n
set __l [info level 0]
lappend ::errorStack $__l
}
# the next line must end with the closing brace on the same line
# in order to consume the extra arguments at runtime.
list }It works by exploiting the fact that ::errorInfo is built progressively while climbing back up the stack; hence, each increment occurs within the scope of each level, and there [info level 0] gives the local function's actual arguments, regardless of whether the variables holding these args have been modified since function entry or not.
if {![regexp {\n invoked from within\n} $::errorInfo]} {
set ::errorLevel -1;
set ::errorStack [list];
}if {[string match {*while executing*} $::errorInfo] == 0} {
set ::errorLevel -1;
set ::errorStack [list];
}-Alex
Twylite 20090227: How does this interact with [catch] in Tcl 8.5 (TIP #90 [L1 ] introduced the options dict) and [try] in Tcl 8.5 (introduced by TIP #329 [L2 ])?
HaO: IMHO the same way as errorInfo, as it is based on its creation. For me, it works with both language extensions and errorStack is correctly created
HaO 2010-12-09: I have included this into my tcl 8.5.9 framework and it is brilliant. Insert the addendum with the regexp at the beginning of the trace write definition and display ::errorStack within a custom bgerror routine together with ::errorInfo. errorInfo tells the error and errorStack the current values. Thank you very much, Alex and Martin!
Interactive sample session after copying the upper lines in a fresh wish interpreter:
% proc e1 args { expr 1/0 }
% proc e2 args { e1 {*}$args }
% e2 1 2 3
divide by zero
% set errorInfo
divide by zero
invoked from within
"expr 1/0 "
(procedure "e1" line 1)
invoked from within
"e1 {*}$args "
(procedure "e2" line 1)
invoked from within
"e2 1 2 3"
% set errorStack
{e1 1 2 3} {e2 1 2 3}HaO 2010-12-15: In interactive mode, the term auto_load_index may appear when a potentially unknown procedure is called.
% proc e args {qq $args}
% e 1 2 3
invalid command name "qq"
% set errorStack
auto_load_index {e 1 2 3}Alex remarked on clt [L3 ], that this is the truth.
HaO 2010-12-16: A bug in 8.5.x - 8.5.9 may cause that traces on error variables crash TCL. . Sorry, this makes this nice trick practically unusable (Discussion: [L4 ], Bug: [L5 ]).