recover

DDG: function which allows you to debug your code more easily. Place it in your code to jump directly in a procedure or namespace for debugging. Works like the R recover function [1 ].

Package code

package provide recover 0.1

namespace eval recover::recover { 
    namespace export recover
}
proc recover::recover {{err ""}} {
    if {$err ne ""} {
        puts "$err"
    } else {
        puts ""
    }
    uplevel 1 {
        set code ""
        puts -nonewline "\ndebug % "
        while {true} {
            gets stdin code
            if {[regexp {^Q\s*} $code]} {
                break
            }
            catch { eval $code } err
            if {$err ne "" } {
                puts "Error: $err"
            }
            puts -nonewline "\ndebug % "
        }
    }
}

Example code to debug

Usage examples:

  • place recover in dubious places in procedures to explore nasty things
  • use recover instead of error before releasing to debug those errors
  • rename recover to error during development to debug directly all errors
package require recover
namespace import recover::recover
# use recover instead of error during development
# that way jump in procedure code if nasty things happen ...
proc recover::sample1 {x} {
    variable v
    array set a [list a 1 b c c 4]
    incr v 1
    if {$x > 5} {
        recover "something went wrong inside sample1"
    }
}

# jump into problematic code
# by adding recover without checks
proc recover::sample2 {x} {
    variable v
    incr v 1
    array set a [list a 1 b c c 4]
    # more complex things
    # something is dubious, place temporarily recover here
    recover
    # more code might follow ...
}

# use rename during debugging to recover in all cases an error occured

rename error error.orig
interp alias {} error {} recover::recover 

proc recover::sample3 {x} {
    variable v
    incr v
    set x 3
    error "Let's recover inside sample 3"
    incr v
}

recover::sample3 4

Session example

$ rlwrap tclsh sample.tcl
Let's recover inside sample 3

debug % puts [info vars]
x v code

debug % puts $x
3

debug % puts $v
1

debug % recover::sample1
Error: wrong # args: should be "recover::sample1 x"

debug % recover::sample1 3
Error: wrong # args: should be "incr varName ?increment?"

debug % source recover.tcl
Let's recover inside sample 3

debug % Q
Error: 3

debug % puts [namespace current]
::recover

debug % recover::sample1 4

debug % recover::sample1 6
something went wrong inside sample1

debug % puts [namespace current]
::recover::recover

debug % puts [info vars]
x v a err code

debug % puts [array names a]
a b c

AMG: The same can be achieved with the idebug command that is provided by Tkcon. See [2 ] for documentation.

Just put [idebug break] in your code in place of [recover], then when you run with [idebug on], you will get a prompt whenever [idebug break] is reached.

Also see Adding breakpoints to TkCon's internal debugger (idebug) for a way to use trace to add idebug breakpoints that doesn't involve editing the procedure bodies.