0

最初に#7755661をご覧ください。私は ECL を使用しており、基本的には何らかのコードを実行し、発生する可能性のあるあらゆる種類の状態をトラップしてから、プロンプトを表示したりデバッガーに入ったりせずに実行を継続したいと考えています。これは、次のハンドラー ケース マクロを使用すると簡単に実現できます。

(handler-case
  (load "code.lisp") ; this may raise a condition

  (error (condition)
    (print condition))) ; this prints sth like #<a UNBOUND-VARIABLE>

私の唯一の問題は、ユーザーにとってより意味のあるエラーを出力する一般的な方法が見つからないことです。実際、私のアプリケーションは HTTP サーバーであり、出力は Web ページに送られます。code.lisp はユーザーによって作成され、あらゆる種類の条件を発生させることができます。コード内でそれらすべてをリストしたいと思います。ハンドラーケースを使用しない場合に REPL に表示されるのと同じエラーメッセージを出力したいだけですが、HTML ページには、たとえば「バインドされていない変数」エラーの場合、「変数 VAR はバインドされていません」のような文字列が表示されます。

タイプの条件オブジェクトUNBOUND-VARIABLEを調べると、2 つのスロットがあることがわかります。SI:REPORT-FUNCTIONはコンパイルされた関数でありSI:NAME、この場合は変数の名前に設定されます。呼び出す必要があると思いSI:REPORT-FUNCTIONますが、どのように呼び出すことができますか? 私が試してみると:

(handler-case foo (error (condition) (SI::REPORT-FUNCTION condition)))

SI:REPORT-FUNCTION が定義されていないことがわかります。ECL の SI または SYS は、実装内部の関数と変数のパッケージですが、動作する限り、コードが移植可能でなくても心配ありません。

SI:FORMAT-CONTROLところで、他の種類の条件オブジェクトには、とという名前の目的のために明らかに役立つ他のスロットもSI:FORMAT-ARGUMENTありますが、コードからもそれらのいずれにもアクセスできません。

getMessage()Lisp の Java 例外オブジェクトのメソッドに似たものを探していましたが、そのようなことについて言及している情報源はありません。

さらに、エラーが発生した code.lisp の行番号も取得できる希望はありますか? これがなければ、ユーザーは自分の code.lisp ソース ファイルで問題を見つけるのが難しくなります。私は本当にこの情報を提供したいと思っており、最初のエラーで停止しても問題ありません。

4

2 に答える 2

3

Common Lisp では、印刷エスケープが無効になっていると、エラー メッセージが表示されます。

 CL-USER > (handler-case
               a       
             (error (condition)
               (write condition :escape nil)))

The variable A is unbound.
#<UNBOUND-VARIABLE 4020059743>

PRINTにバインド*print-escape*されることに注意してくださいT

作品の使用PRINC- にバインド*print-escape*NILます。

CL-USER > (handler-case
              a                
            (error (condition)
              (princ condition)))

The variable A is unbound.
#<UNBOUND-VARIABLE 4020175C0B>

これは、CLHS 9.1.3 印刷条件に記載されています。

また、スロットを持つオブジェクトがあり、このスロットの値が関数である場合、関数を使用してスロット値を取得し、正しい引数で関数をSLOT-VALUE使用FUNCALLまたは呼び出す必要があることに注意してください。APPLY

type の条件がある場合simple-conditionは、format-control と format-argument 情報があります。FORMATこれは、CLHS Function SIMPLE-CONDITION-FORMAT-CONTROL、SIMPLE-CONDITION-FORMAT-ARGUMENTSでの使用方法の例で説明されています。

于 2012-06-06T16:16:37.060 に答える
2

以下の私の回答は、ECL メーリング リストで既に提供したものに基づいています。実際には、これは組み込みの問題ではなく、Lisp の問題であると私は主張します。エラーの原因となったフォームのファイル位置にある情報を取得したいとします。条件は、評価されたフォームが解釈されたか、コンパイルされたか、Lisp イメージに既にインストールされている関数の一部であるかに関係なく発生するため、これは条件に関連付けられません。言い換えれば、読み取られているファイルの位置を知り、情報を追加するラッピングを行うのはあなた次第です。

以下は非標準であり、変更される可能性があります: ECL は、ソース ファイルで LOAD が使用されている場合、変数 ext:: source-locationを定義することによって役立ちます。この変数には、ユーザーが決して変更または保存してはならない CONS が含まれていますが、ファイルを として(CAR EXT:*SOURCE-LOCATION*)、ファイルの位置を として取得できます(CDR EXT:*SOURCE-LOCATION*)。計画は、LOAD フォームを HANDLER-BIND 内に埋め込むことです。

(defparameter *error-message* nil)
(defparameter *error-tag* (cons))

(defun capture-error (condition)
   (setf *error*
      (format nil "At character ~S in file ~S an error was found:~%~A"
         (cdr ext:*source-location*)
         (car ext:*source-location*)
         condition)))
  (throw *error-tag* *error-message*))

(defun safely-load (file)
  (handler-bind ((serious-condition #'capture-error))
      (catch *error-tag*
        (load file)
        nil)))

(SAFELY-LOAD "myfile.lisp")NIL またはフォーマットされたエラーのいずれかを返します。

いずれにせよ、これを LOAD に頼るのは失敗する運命にあると私は強く信じています。これから始めて、独自のバージョンの LOAD を作成する必要があります。

(defun my-load (userfile)
  (with-open-file (stream userfile :direction :input :external-format ....whateverformat...)
     (loop for form = (read stream nil nil nil)
        while form
        do (eval-form-with-error-catching form))))

ここで、EVAL-FORM-.... は上記のコードのようなものを実装します。この関数はより洗練されたものにすることができ、ファイルの位置、行番号などを追跡することができます。この方法でコードの移植性も向上します。

ですから、ANSI 仕様を読んで言語を学んでください。条件を読みやすく出力する方法を知らず、代わりに ECL 内部をいじろうとしたという事実は、移植性のない解決策 (非表示のスロット名、レポート関数など) を使用しようとして、将来さらに問題に直面する可能性があることを示しています。最初に標準的な方法を試す代わりに。

于 2012-06-08T08:07:38.120 に答える