2012-06-06 4 views
0

먼저 #7755661을 참조하십시오. ECL을 사용하고 있으며 기본적으로 일부 코드를 실행하고 발생할 수있는 모든 종류의 조건을 트랩 한 다음 디버거에 메시지를 표시하거나 입력하지 않고 계속 실행하려고합니다. 여기에는 다음 핸들러의 경우 매크로 달성하기 쉽습니다 :Embedded ECL Lisp 오류 처리 기본 오류 문자열 및 가능한 줄 번호를 가져옵니다.

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

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

내 유일한 문제는 내가 사용자에게보다 의미있는 오류를 인쇄하는 일반적인 방법을 찾을 수 있다는 것입니다. 사실 내 응용 프로그램은 HTTP 서버이며 출력은 웹 페이지로 이동합니다. code.lisp은 사용자가 작성하고 모든 종류의 조건을 발생시킬 수 있습니다. 이제는 모든 코드를 내 코드에 나열하려고합니다. 핸들러 - 케이스를 사용하지 않을 때 REPL에서 볼 수있는 것과 동일한 오류 메시지를 인쇄하고 싶지만 HTML 페이지에서는 예를 들어 "언 바운드 변수"오류의 경우 "변수 VAR이 언 바운드"와 같은 문자열입니다.

유형 객체 UNBOUND-VARIABLE을 검사하면 두 개의 슬롯이 있습니다.이 경우에는 컴파일 된 함수 인 SI:REPORT-FUNCTION이고이 경우에는 SI:NAME이 변수의 이름으로 설정됩니다. 나는 SI:REPORT-FUNCTION 내가 호출 할 필요가있을 수 있지만 어떻게 부를 수 있을까요? 시도한 경우 :

SI : REPORT-FUNCTION은 정의되지 않았습니다. ECL의 SI 또는 SYS는 구현 내부의 함수 및 변수를위한 패키지이지만 작동하는 한 내 코드가 이식 가능하지 않더라도 걱정하지 않습니다.

다른 종류의 조건 개체에는 또한 내 용도로 다른 용도로도 유용한 슬롯이 있습니다. 이름은 SI:FORMAT-CONTROLSI:FORMAT-ARGUMENT이지만 내 코드에서도 액세스 할 수 없습니다.

나는 Lisp의 getMessage() Java 예외 객체의 메소드와 비슷하게 비슷하게 찾고 있었지만, 내 소스 중 어느 것도 그런 식으로 언급하지 않았다.

또한 오류가 발생한 code.lisp에서 줄 번호를 가져올 수있는 희망이 있습니까? 그것 없이는 사용자가 code.lisp 소스 파일에서 문제를 찾을 수 없을 것입니다. 나는이 정보를 제공하고 싶을 것이고 첫 번째 오류에서 멈추는 것은 나를 받아 들일 만하다.

답변

3

인쇄용 이스케이프 기능을 사용할 수없는 경우 Common Lisp에서 오류 메시지가 인쇄됩니다. PRINTT*print-escape*를 결합하는 것을

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

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

참고.

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 Printing Conditions에 설명되어 있습니다.

또한 당신이 슬롯이 슬롯의 값을 갖는 함수는 객체를 가질 때, 다음 함수 SLOT-VALUE를 사용하여 슬롯 값을 가져온 다음 FUNCALL 또는 APPLY를 사용하여 함수를 호출 할 필요가 있습니다 올바른 인수.

유형이 simple-condition 인 경우 형식 제어 및 형식 인수 정보가 있습니다.이것은 FORMAT에서 CLHS Function SIMPLE-CONDITION-FORMAT-CONTROL, SIMPLE-CONDITION-FORMAT-ARGUMENTS

+0

감사합니다. Lisp 해커! 그것은 의미가 있습니다, 나는 인쇄물의 출력이 읽기 쉽다는 것을 잊었습니다! 어쨌든, 표준에는 몇 가지 단점이 있으며 우리는 그것을 바꿀 수 없습니다 : (예를 들어, 줄 수를 인쇄하는 것에 대해서는 단서가 없습니다.) –

+0

@Antonio Bonifati : Lisp 구현이 에러 위치를 어떻게 다루는 지에 대해서는 크게 차이가 있습니다. 예를 들어 LispWorks는 '소스 로케이터'에 대한 아이디어를 가지고 있습니다 (소스는 청취자, 편집자 버퍼, 파일 등에서도 얻을 수 있습니다). ECL이 뭔가를 제공하는지 모르겠다. –

2

에 사용하는 예제와 함께 설명됩니다. 내 대답은 이미 ECL 메일 링리스트에서 이미 제공 한 답변을 기반으로합니다. 사실 나는 이것이 임베딩 문제가 아니라 Lisp이라고 주장한다. 오류의 원인이 된 양식의 파일 위치에서 정보를 얻으려고합니다. 조건은 평가 된 양식이 해석되었거나, 컴파일되었거나, Lisp 이미지에 이미 설치된 함수의 일부인지 여부에 관계없이 발생하기 때문에 조건에 첨부되지 않습니다. 즉, 읽히는 파일의 위치를 ​​알아 내고 정보를 추가하는 줄 바꿈을하는 것은 독자의 몫입니다.

다음은 비표준이며 변경 가능성이 있습니다. ECL은 소스 파일에 LOAD가 사용될 때 ext :: 소스 위치 변수를 정의하여 도움이됩니다. 이 변수에는 사용자가 변경하거나 저장해서는 안되는 단점이 있지만, 파일을 (CAR EXT:*SOURCE-LOCATION*), 파일 위치를 (CDR EXT:*SOURCE-LOCATION*)으로 가져올 수 있습니다. 이 계획은 NIL 또는 형식의 오류 중 하나를 반환하는 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") 내부에 LOAD의 양식을 삽입하는 것입니다.

나는 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 내부에서 쉽게 읽을 수있는 상태를 인쇄하는 법을 알지 못 했으므로 미래의 다른 문제 (예 : 숨겨진 슬롯 이름, 보고서 기능 등)로 이동하려고 시도 할 수 있음을 보여줍니다. 먼저 표준 방식을 시도하는 대신