tcl how to get command executed in which file and which line?

78 views Asked by At

how to know when I source the tcl script, which proc/eval is executed in which file & which line?

below is my code:

 set counts     [info frame];
 set frame_list [info frame [expr {$counts - 2}] ]   ; #for cmd type is "eval"
 set frame_list [info frame [expr {$counts - 1}] ]   ; #for cmd type is other like "source"
 [dict get $frame_list file] # to get file
 [dict get $frame_list line] # to get line in file

but sometime in script there is internal eval in file, let the frame_list get error level info. how to let tcl get correct file&line?

2

There are 2 answers

0
Cyan Ogilvie On

I think you want interp debug {} -frame true, which (at substantial performance cost) enables additional accounting to resolve the file and line numbers of frames in more situations:

Without:

proc dothing script {
    eval $script
}

proc foo {} {
    dothing {
        puts "In dothing: [info frame 0]"
    }
}

foo

prints In dothing: type eval line 2 cmd {info frame 0} proc ::dothing level 0

With debug -frame true:

interp debug {} -frame true

proc dothing script {
    eval $script
}

proc foo {} {
    dothing {
        puts "In dothing: [info frame 0]"
    }
}

foo

prints In dothing: type source line 9 file /home/cyan/git/research/tcl/frame/without.tcl cmd {info frame 0} proc ::dothing level 0

(Tcl is able to turn the type eval frame into a type source frame in the report because it has enough info from interp debug {} -frame true).

But there are still many situations where it's not possible to do that:

interp debug {} -frame true

proc dothing script {
    eval $script
}

proc foo {} {
    set s {
        puts "In dothing: [info frame 0]"
    }
    dothing $s
}

foo

Still prints In dothing: type eval line 2 cmd {info frame 0} proc ::dothing level 0

This example (eval on a variable which contains a string literal defined in a source file) might be possible to resolve with enough work in the Tcl core (I have experiments that track scripts back to literals in this way), but there will always be others where it's just not possible (like the script being run was received over a network socket - it's just a value and doesn't have a source location in a file, or a script dynamically built up by other code). So there is no universal way to always get a type source frame report.

Also note that enabling frame debug on an interp is a one way operation - once it's been enabled it stays enabled, no way to turn it off again. So watch out for the performance hit if you're working on something where performance matters.

0
Donal Fellows On

Sometimes the file and line information simply isn't known to the runtime. This is particularly the case for any generated code; it just doesn't tie back to a specific source location. (There are other cases where this is true, but I can't remember them right now except for when dealing with encrypted code, which isn't something that happens in an ordinary Tcl interpreter.)

When you use info frame, you just need to be aware that many of the keys are not necessarily there.