информация трассировки стека в errorInfo в Tcl - PullRequest
4 голосов
/ 03 февраля 2010

При использовании Tcl в интерактивном режиме, в котором я ввожу следующее:

set list {1 2 3 4 5}
set sum 0
foreach el $list {
    set sum [expr $sum + $element]
}

покажет очень краткую информацию:

can't read "element": no such variable

но когда я использую

puts $errorInfo

покажет:

can't read "element": no such variable
      while executing
"expr $sum + $element"
      ("foreach" body line 2)
      invoked from within
"foreach el $list {
      set sum [expr $sum + $element]
 }"

это то, чего я действительно хочу.

Проблема в том, что в неинтерактивном режиме, когда я хочу перехватить эту ошибку, а затем помещает errorInfo, чтобы получить трассировку стека, он просто отображает краткую информацию. Как получить подробную трассировку стека, как указано выше? Большое спасибо!

Отредактировано, чтобы добавить больше деталей

скажем, у меня есть следующий код:

proc test1 {} {
    set list {1 2 3 4 5}
    set sum 0
    foreach el $list {
    if {[catch {set sum [expr $sum + $element]} err]} {
        puts $::errorInfo
    }
    break 
    }
}
proc test2 {} {
    foreach el $list {
    set list {1 2 3 4 5}
    set sum 0
    set sum [expr $sum + $element]
    }
}    
#test1
#test2

Если я раскомментирую "# test1", он покажет:
не могу прочитать "элемент": нет такой переменной
при выполнении
"expr $ sum + $ element"

если я раскомментирую "# test2", он покажет:
не может прочитать "элемент": такой переменной нет
во время выполнения "expr $ sum + $ element"
(процедура "test2" строка 5)
вызывается изнутри
"Test2"
(файл "./test.tcl" строка 137)

Я хочу, конечно, поведение test2. Как я могу отобразить эту информацию об ошибке, используя catch?

Ответы [ 3 ]

8 голосов
/ 03 февраля 2010

Можете ли вы показать, как вы ловите / помещаете информацию в неинтерактивном режиме?

Если вы сделали

if {[catch {...your...code...here...} err]} {
   puts "Error info $err"
}

Тогда описанное вами поведение ожидается - $err имеет только"краткая информация".Вместо этого вам может потребоваться puts:

   puts "Error info $err\nFull info: $::errorInfo"

Префикс :: необходим в случае, если ваш catch вызывается внутри proc или пространства имен, чтобы убедиться, что используемая переменная является фактическим toplevel:: errorInfo.

Отредактировано для решения вопроса

Когда Колин ответил , трассировки стека, найденные в ваших test1 и test2, отличаютсяиз-за того, где вы разместили улов.Позвольте мне проиллюстрировать.Вот несколько цепочек Tcl-процессов:

proc one {} {
  two
}
proc two {} {
  three
}
proc three {} {
  four
}
proc four {} {
  error "Yup, an error"
}

Если вы оцените

catch {four}
puts $::errorInfo

Вы просто получите трассировку стека, которая выглядит следующим образом:

Yup, an error
    while executing
"error "Yup, an error""
    (procedure "four" line 2)
    invoked from within
"four"

Thisэто потому, что трассировка стека между тем, где произошла ошибка (внутри four), и тем местом, где вы ее уловили, вызывает только один вызов процедуры.

Если вместо этого вы поймали ошибку «еще дальше», например:*

catch {one}
puts $::errorInfo

Трассировка стека между оператором catch и ошибкой включает в себя процедуры one, two, three и four.Это приводит к трассировке стека примерно так:

Yup, an error
    while executing
"error "Yup, an error""
    (procedure "four" line 2)
    invoked from within
"four"
    (procedure "three" line 2)
    invoked from within
"three"
    (procedure "two" line 2)
    invoked from within
"two"
    (procedure "one" line 2)
    invoked from within
"one"

Итак ... в соответствии с вашим примером для test1, если вы переопределите three следующим образом:

proc three {} {
  catch {four}
  puts $::errorInfo
}

ИВы оценили

if {[catch {one}]} {
   puts "Found an error"
}

Вы бы не см. "Обнаружена ошибка", поскольку тело three обнаружило ошибку и напечатало трассировку стека.Трассировка стека содержит только вызовы между оператором catch и ошибкой, которая (как и мой первый пример) состоит только из вызова four.

Итак, где вы размещаете операторы catchВопрос.


В связанной заметке вы можете повторно выдать ошибку, сохранив трассировку стека, если вы того пожелаете.Вот новое определение для three:

proc three {} {
  if {[catch {four} err]} {
    puts "Caught an error $err, re-throwing"
    error $err $::errorInfo
  }
}

Теперь, с повторно выданной ошибкой, вы увидите это:

tchsh% catch {one}
Caught an error Yup, an error, re-throwing
1
tclsh% set ::errorInfo
Yup, an error
    while executing
"error "Yup, an error""
    (procedure "four" line 2)
    invoked from within
"four"
    (procedure "three" line 2)
    invoked from within
"three"
    (procedure "two" line 2)
    invoked from within
"two"
    (procedure "one" line 2)
    invoked from within
"one"
1 голос
/ 04 февраля 2010

Учитывая дальнейшее уточнение вашего вопроса, вам может помочь следующее:

# gets the stack up to the caller
proc get_stack {} {
    set result {}
    for {set i [expr {[info level] -1}]} {$i >0} {incr i -1} {
        lappend result [info level $i]
    }
    return $result
}

# formats the stack for display
proc format_stack {stackList} {
    return "\twhile executing: [join $stackList \n\twhile\ executing:\ ]"
}

# test function that has an error
proc test3 {x y} {
    set list {1 2 3 4 5}
    set sum 0
    foreach el $list {
        if {[catch {set sum [expr $sum + $element]} err]} {
            puts "$::errorInfo\n[format_stack [get_stack]]"
        }
        break 
    }
}

# wrapper test function, just so we can show the call stack more visibly
proc test4 {a b c} { 
    test3 A B
}

# and, we call it and show the output
% test4 1 2 3
can't read "element": no such variable
    while executing
"expr $sum + $element"
    while executing: test3 A B
    while executing: test4 1 2 3
0 голосов
/ 03 февраля 2010

Зависит от того, как близко к месту ошибки вы его ловите.Трассировка стека в errorInfo создается по мере того, как стек разматывается с места ошибки обратно к первому включающему улову или верхнему уровню - см. Учебник Так что если у вас есть перехват в процедуре, где происходит ошибка, у вас не будет возможности построить трассировку стека в errorInfo.

...