发出信号时调用调试器的条件?

时间:2012-11-30 14:39:13

标签: common-lisp

我正在尝试做什么: 我希望simple-error的功能出现在另一个错误中。我出于以下原因想要这个:

  • 能够在handler-case的单独条款中处理它。

  • 以避免一遍又一遍地指定消息字符串...

  • 在发生错误时调用调试器。

我有点困惑,默认情况下这不会自然发生,从来没有对这个问题给予足够的重视,但这显然是它的功能......我能做的就是发出错误信号,我就是以后可以处理handler-casehandler-bind,但这很糟糕,因为我不会总是记住函数是否抛出,当它抛出时,但我忘了处理它,函数只是早点回来,仿佛什么都没发生。但是,如果我继续使用simple-error,那么我的代码将开始如下:

...
(signal "Container ~S has no key ~S~&" :container foo :key bar)
...
(signal "Container ~S has no key ~S~&" :container foo :key baz)
...

等等,到处都是:/当然我可以专门用一个变量来保存消息文本,也许有一个宏来缩短它,但这实际上没有用,因为它只隐藏了实际的混乱而不是解决问题。

到目前为止,我能做些什么:

(define-condition missing-key (condition)
  ((key :initarg :key
        :accessor key-of)
   (container :initarg :container
              :accessor container-of))
  (:documentation
   "An error rised when a KEY is not in the CONTAINER"
   :report
   #'(lambda (condition stream)
       (unless *print-escape*
         (format stream "~&Container ~S has no key ~S"
                 (container-of condition)
                 (key-of condition))))))

(handler-bind
    ((missing-key
      #'(lambda (condition)
          (invoke-debugger condition))))
  (signal 'missing-key :key 'foo :container 'bar))
然而,会发生什么,报告函数永远不会被调用...当发出错误信号时,它会输出一般信息Condition MISSING-KEY was signalled.

编辑:

感谢sds回答,这就是我现在所拥有的:

(define-condition missing-key (error)
  ((key :initarg :key
        :accessor key-of)
   (container :initarg :container
              :accessor container-of))
  (:documentation
   "An error rised when a KEY is not in the CONTAINER")
  (:report
   (lambda (condition stream)
     (format stream "Container ~S has no key ~S"
             (container-of condition)
             (key-of condition)))))

(defmacro signal-missing-key (container key)
  `(let ((*break-on-signals*
          (cond
            ((null *break-on-signals*) 'missing-key)
            ((consp *break-on-signals*)
             (list 'or 'missing-key (cdr *break-on-signals*)))
            (t (list 'or *break-on-signals* 'missing-key)))))
     (signal 'missing-key :key ,container :container ,key)))

我可以通过将更多参数传递给signal来使它更通用,但是这样做我最初想做的事情,所以,除非有更好的方法做同样的事情,我可能会只是用这个。

3 个答案:

答案 0 :(得分:2)

您的代码按预期工作,并进行了以下修改:在#'之前删除lambda,从~&删除format(错误报告执行此操作等),关闭:documentation子句并打开:report子句:

(define-condition missing-key (condition)
  ((key :initarg :key
        :accessor key-of)
   (container :initarg :container
              :accessor container-of))
  (:documentation
   "An error rised when a KEY is not in the CONTAINER")
  (:report
   (lambda (condition stream)
       (unless *print-escape*
         (format stream "Container ~S has no key ~S"
                 (container-of condition)
                 (key-of condition))))))
MISSING-KEY
(signal 'missing-key :key 'foo :container 'bar)
==> NIL
(handler-bind
    ((missing-key
      #'(lambda (condition)
          (invoke-debugger condition))))
  (signal 'missing-key :key 'foo :container 'bar))


*** - Container BAR has no key FOO
The following restarts are available:
ABORT          :R1      Abort main loop
Break 1 [46]> 

即,signal只打印handler调用调试器。

答案 1 :(得分:2)

如果您希望调用调试器,则可以将errorcerror与您自己的条件类型一起使用,除非以其他方式处理条件。这也适用于不是simple-error的后代的条件。

如果您对signal也有此行为,则可以将变量*break-on-signals*设置为相应的类型。例如,您可以将其设置为t,以便为每个未处理的条件调用调试器。

答案 2 :(得分:1)

使您的条件成为ERROR的子类,而不是CONDITION。并非所有条件都是需要通过调试器进行干预的错误,条件类层次结构旨在区分它们。