Tcl: Есть ли способ показать, какая строка в tcl выдает ошибку?

#tcl

#tcl

Вопрос:

Когда я создаю файл tcl, при запуске неизвестной команды будет сообщаться об ошибке.

 Tcl> source run.tcl
$inside tcl file$$> setup_desgin
    Design setup...
    Done
$inside tcl file$$> my_prove
    Info: proving started
    Info: ....
    Info: ....
$inside tcl file$$> ::unknown my_pro
    invalid command name "my_pro"
  

Есть ли способ показать номер строки строки ошибки в файле tcl, как показано ниже?

 Tcl> source run.tcl
$inside tcl file$$> setup_desgin
    Design setup...
    Done
$inside tcl file$$> my_prove
    Info: proving started
    Info: ....
    Info: ....
$inside tcl file$$> ::unknown my_pro
    invalid command name "my_pro" (run.tcl:5)
  

Мы хотим этого, потому что у нас может быть очень большой run.tcl с приспешниками line.

Ответ №1:

На самом деле довольно сложно получить эту информацию в целом. Точная информация о номере строки доступна только в настоящее время, когда код находится в стеке выполнения. К счастью, вы можете узнать, что происходит, с помощью трассировки с шагом оставления (перехват unknown будет работать только для неизвестных команд; трассировка позволяет перехватывать все ошибки). В приведенном ниже коде я включил его eval , но в более практическом примере вы бы включили его source или что-то в этом роде.

 set errorlineSet 0
proc LEAVESTEP {cmd code result op args} {
    global errorline errorlineSet
    if {$code == 1} {
        if {!$errorlineSet} {
            set errorline [dict get [info frame -4] line]
        }
        set errorlineSet 1
    } else {
        set errorlineSet 0
    }
}

try {
    trace add execution eval leavestep LEAVESTEP
    eval {
        sdfgsldfjg;   # This is line 17
    }
} on error {msg opt} {
    puts "ERROR: $msg (line: $errorline) (local line: [dict get $opt -errorline])"
} finally {
    trace remove execution eval leavestep LEAVESTEP
}
  

Когда я сохраняю все это в файл и запускаю его, он выводит это:

 ERROR: invalid command name "sdfgsldfjg" (line: 17) (local line: 3)
  

Как вы можете видеть, в -errorline словаре параметров результата также есть ключ, но 3 в данном случае он сопоставлен, и это довольно вводит в заблуждение! Он использует это значение из-за обратной совместимости, но я не уверен, что это все так полезно.

Комментарии:

1. Это -4 было обнаружено экспериментально; Мне всегда приходится искать, пока я не получу правильное значение экспериментальным путем. Наличие трассировок шагов выполнения влияет на это значение.

2. Кажется, tcl8.4 не поддерживает опцию «frame» для команды «info»

Ответ №2:

Вы можете переопределить unknown команду и использовать info frame команду в ней, чтобы получить местоположение. Что-то вроде:

 # Save the default unknown if you want
rename ::unknown ::original_unknown

proc ::unknown {name args} {
    set caller [info frame -1]
    dict with caller {
        switch $type {
            source {
                puts stderr "invalid command name "$name" (in file $file:$line)"
            }
            proc {
                if {[info exists lambda]} {
                    puts stderr "invalid command name "$name" (in lambda $lambda:$line)"
                } else {
                    puts stderr "invalid command name "$name" (in proc $proc:$line)"
                }
            }
            eval {
                puts stderr "invalid command name "$name" (in eval {$cmd}:$line)"
            }
            precompiled {
                puts stderr "Invalid command name "$name""
            }
        }
    }
}
  

Пример использования:

 % source my_unknown.tcl
% source bad.tcl
invalid command name "put" (in file /home/shawn/src/bad.tcl:3)