Можно ли включить выход при возникновении ошибки в интерактивной оболочке Tcl? - PullRequest
0 голосов
/ 21 октября 2019

Мне нужно автоматизировать огромную интерактивную программу Tcl с использованием ожидаемого Tcl.

Как я понял, эта территория действительно опасна, поскольку мне нужно расширить уже существующую массу кода, но я не могу полагатьсяна ошибки, которые фактически приводили к сбою программы с положительным кодом выхода, как я мог в обычном скрипте. Это означает, что я должен думать о каждой возможной вещи, которая может пойти не так, и «ожидать» ее.

В настоящее время я использую процедуру «die» вместо сообщения об ошибке в моем собственном коде, который автоматически завершается,Но этот тип ошибки не может быть catch ed и затрудняет обнаружение ошибок, особенно в коде, не написанном мной, так как в конечном итоге большинство библиотечных подпрограмм будет error.

Так какУ меня есть доступ к программной оболочке Tcl, возможно ли включить Fail-on-Error?

РЕДАКТИРОВАТЬ:

Я использую Tcl 8.3, что является серьезным ограничением с точки зрения доступных инструментов.

Примеры ошибок, с которыми я хотел бы автоматически выйти:

% puts $a(2)
can't read "a(2)": no such element in array
while evaluating {puts $a(2)}
%

% blublabla
invalid command name "blublabla"
while evaluating blublabla
% 

Как и любая другая ошибка, которая приводит к завершению обычного сценария. Они могут подниматься до 10 уровней внутри вызовов процедур.

Я также пытался переопределить глобальную команду error, но не все ошибки, которые могут возникнуть в Tcl, используют ее. Например, вышеприведенная ошибка «команда не найдена» не прошла мою пользовательскую процедуру error.

1 Ответ

0 голосов
/ 22 октября 2019

Так как у меня есть доступ к программной оболочке Tcl, возможно ли включить функцию сбоя при ошибке?

Позвольте мне попытаться подвести итог своими словами: Вы хотите выйти изинтерактивная оболочка Tcl при ошибке, вместо того, чтобы снова предлагать приглашение?

Обновление

Я использую Tcl 8.3, что является серьезным ограничением с точки зрения доступных инструментов [.. .] только исходные патчи для кода C.

Поскольку вы, кажется, глубоко в этой кроличьей норе, почему бы не добавить еще один патч для исходного кода?

--- tclMain.c   2002-03-26 03:26:58.000000000 +0100
+++ tclMain.c.mrcalvin  2019-10-23 22:49:14.000000000 +0200
@@ -328,6 +328,7 @@
        Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
        Tcl_WriteChars(errChannel, "\n", 1);
        }
+       Tcl_Exit(1);
    } else if (tsdPtr->tty) {
        resultPtr = Tcl_GetObjResult(interp);
        Tcl_GetStringFromObj(resultPtr, &length);

Это не провереноисходники Tcl 8.3.5 для меня не компилируются. Но этот внутренний раздел Tcl сравним с текущими источниками, протестированными с использованием моей исходной установки Tcl 8.6.

Для записей

С обычной оболочкой (tclsh) это немного сложновато, Я боюсь. Следующее может работать для вас (хотя, я могу представить случаи, когда это может вас подвести). Идея состоит в том, чтобы

  • перехватывать записи в stderr (именно здесь интерактивная оболочка перенаправляет сообщения об ошибках перед возвратом к приглашению).
  • Чтобы различить произвольные записи в stderr и случаи ошибок, можно использовать глобальную переменную ::errorInfo в качестве часового.

Шаг 1: Определить перехватчик канала

oo::class create Bouncer {
    method initialize {handle mode} {
        if {$mode ne "write"} {error "can't handle reading"}
        return {finalize initialize write}
    }
    method finalize {handle} {
        # NOOP
    }

    method write {handle bytes} {
        if {[info exists ::errorInfo]} {
        # This is an actual error;
        # 1) Print the message (as usual), but to stdout
        fconfigure stdout -translation binary
        puts stdout $bytes
        # 2) Call on [exit] to quit the Tcl process
        exit 1
    } else {
        # Non-error write to stderr, proceed as usual
            return $bytes
    }
    }
}

Шаг 2: Зарегистрируйте перехватчик для stderr в интерактивных оболочках

if {[info exists ::tcl_interactive]} {
    chan push stderr [Bouncer new]
}

После регистрации ваша интерактивная оболочка будет вести себя так:

% puts stderr "Goes, as usual!"
Goes, as usual!
% error "Bye, bye"
Bye, bye

Некоторые замечания

  • Вы должны быть осторожны с методом Bouncer write, сообщение об ошибке уже замаскировано для кодировки символов (следовательно, вызов fconfigure).
  • Возможно, вы захотите поместить это в пакет Tcl или модуль Tcl, чтобы загрузить баунсер, используя package req.
  • Я мог бы представить, что ваша программа пишет в stderr и errorInfo переменная может быть установлена ​​(как оставленная), это вызовет непреднамеренный выход.
...