Reading Debugger output in Komodo IDE for Tcl Languare

160 Views Asked by At

I am trying to understand errors and exceptions in Tcl. I have written a small code as follows

proc Div3 {a b} {
    return [Div2 $a $b]
}

proc Div2 {a b} {
    return [Div $a $b]
}

proc Div {a b} {
   if {$b == 0} {
      error "Error generated by error" "Info String for error" 401
   } else {
      return [expr $a/$b]
   }
}

if {[catch {puts "Result = [Div3 10 0]"} errmsg]} {
   puts "ErrorMsg: $errmsg"
   puts "ErrorCode: $errorCode"
   puts "ErrorInfo:\n$errorInfo\n"
}

when I run this using tclsh.exe, the debugger output is shown as follows,

% tclsh error-file-1.tcl
ErrorMsg: Error generated by error
ErrorCode: 401
ErrorInfo:
Info String for error
    (procedure "Div" line 1)
    invoked from within
"Div $a $b"
    (procedure "Div2" line 2)
    invoked from within
"Div2 $a $b"
    (procedure "Div3" line 2)
    invoked from within
"Div3 10 0"

However, when I run the same using tclsh.exe via Komodo IDE, I am getting the debugger output as follows

ErrorMsg: Error generated by error
ErrorCode: 401
ErrorInfo:
Info String for error
    invoked from within
"DbgNub_uplevelCmd 1 $cmd"
    invoked from within
"Div $a $b"
    invoked from within
"DbgNub_uplevelCmd 1 $cmd"
    invoked from within
"Div2 $a $b"
    invoked from within
"DbgNub_uplevelCmd 1 $cmd"
    invoked from within
"Div3 10 0"
    invoked from within
"DbgNub_uplevelCmd 1 $cmd"
    invoked from within
"DbgNub_Do 0 {1 17 {249 27}} {puts "Result = [DbgNub_Do 1 {1 17 {265 9}} {Div3 10 0}]"}"

I can understand the debugger output from tclsh.exe but unable to interpret the debugger output from Komodo IDE.

especially, I am unable to understand DbgNub_Do 0 {1 17 {249 27}} {puts "Result = [DbgNub_Do 1 {1 17 {265 9}} {Div3 10 0}]"} what are the number shown in the lists (i.e {1 17 {249 27}}) and DbgNub_uplevelCmd 1 $cmd and DbgNub_Do

Thanks in advance

1

There are 1 best solutions below

1
On

All the DbgNub_ commands mentioned in the stack trace are Komodo's extra debugging instrumentation (hiding them in the stack trace is theoretically possible, but messy and the instrumentation obviously doesn't actually do it). Generally, you probably ignore those commands as they're not going to be there when you deploy.

If we ignore the DbgNub_uplevelCmd bits, we get:

Info String for error
    invoked from within
"Div $a $b"
    invoked from within
"Div2 $a $b"
    invoked from within
"Div3 10 0"
    invoked from within
"DbgNub_Do 0 {1 17 {249 27}} {puts "Result = [DbgNub_Do 1 {1 17 {265 9}} {Div3 10 0}]"}"

That's recognisably similar to the standard trace except for the lack of line number information (and the DbgNub_Do, which is obviously instrumenting the code inside the catch directly).


Generally, Tcl's result status consists of:

  1. A result code. This is TCL_OK (= 0) on success of a piece of code, TCL_ERROR (= 1) if an exception was thrown, and a few other values for other things (TCL_RETURN, TCL_BREAK and TCL_CONTINUE). Those names are defined at the C level.
  2. A result value that is stored in the interpreter. In ancient versions of Tcl this was a simple string, but it's been a reference-counted typed value for over 20 years. (Tcl does have a type system. It's just very different from every other language's in that strings are the supertype of all other types.)
  3. A result dictionary that contains additional information. Standard entries (it's possible to define your own too) in this are:
    1. The error information, a.k.a stack trace that gets written to the errorInfo global to support old code. Only really meaningful for errors.
    2. The error code, a machine readable exception descriptor that gets written to the errorCode global to support old code. Again, only really meaningful for errors.
    3. The error line. The bit that's used to generate the number in the message (procedure "Div" line 1) and so on.
    4. The level, which is used by return to do multi-level returns.

There's some other bits and pieces that only kick in in a few cases (such as when a try's finally clause throws an exception when the body of the exception threw, a gnarly case in lots of languages).