Version 0 of Steppin' out

Updated 2002-12-18 08:42:28

Richard Suchenwirth 2002-12-17 - This is my first experiment with the command traces introduced in Tcl 8.4: step through certain procs, so that every command inside the body is displayed before execution, and its result after, while allowing to execute arbitrary Tcl commands at such step positions. This is of course a powerful debugging tool

The code below requires stdin/out, so under Windows is best run from a tclsh. At the stepping prompt, <Return> lets you advance through the code. What troubled me on my 8.4.0/W95 installation at home is that for all but the first command, leavestep traces fired even before enterstep traces (with empty string result) - wonder whether that's a bug (same on 8.4.1/W2k)... Also, when I provoked an error with the uncommented kaboodle command below, stepping continued into unknown, which was interesting to observe but not what the doctor ordered. }

 proc stepping name {
    trace add exec $name enterstep enterStep
    trace add exec $name leavestep leaveStep
 }
 proc noStepping name {
    trace remove exec $name enterstep enterStep
    trace remove exec $name leavestep leaveStep
 }
 proc enterStep {cmd _} {uplevel 1 [list bp "before $cmd"]}

 proc leaveStep {cmd code result _} {
    uplevel 1 [list bp "result ($code):$result<=$cmd"]
 }

#-- reusable breakpoint handler from A minimal debugger

 proc bp s {
    if {[string length $s]>50} {set s [string range $s 0 49]...}
    while 1 {
        puts -nonewline "$s > "
        flush stdout
        gets stdin line
        if {$line==""} break
        catch {uplevel 1 $line} res
        puts $res
    }
 }

#-------- Testing...

 if {[file tail [info script]] == [file tail $argv0]} {
     proc foo x {
        puts "This is foo"
        set i 0
        while {$i < $x} {
            puts "i=$i"
            incr i
        }
        #kaboodle
        puts "That was foo"
    }
    stepping foo
    foo 3
 }

#--- Sample session:

 before puts {This is foo} >
 This is foo
 result (0):<=puts {This is foo} >
 result (0):<=set i 0 >
 before set i 0 >
 result (0):0<=set i 0 >
 result (0):<=while {$i < $x} {
            puts "i... >
 before while {$i < $x} {
            puts "i=$i"
 ... >
 result (0):<=puts i=0 > info locals
 x i
 result (0):<=puts i=0 > set x
 3
 result (0):<=puts i=0 >
 before puts i=0 >
 i=0
 result (0):<=puts i=0 >
 result (0):<=incr i >
 before incr i >
 result (0):1<=incr i >
 result (0):<=puts i=1 >
 before puts i=1 >
 i=1
 result (0):<=puts i=1 >
 result (0):<=incr i >
 before incr i >
 result (0):2<=incr i >
 result (0):<=puts i=2 >
 before puts i=2 > info pa
 8.4.1
 before puts i=2 >
 i=2
 result (0):<=puts i=2 >
 result (0):<=incr i >
 before incr i >
 result (0):3<=incr i >
 result (0):<=while {$i < $x} {
             puts "i... >
 result (0):<=puts {That was foo} >
 before puts {That was foo} >
 That was foo
 result (0):<=puts {That was foo} >