1 ;;;;------------------------------------------------------------------
3 ;;;; Copyright (C) 2001-2005,
4 ;;;; Department of Computer Science, University of Tromso, Norway.
6 ;;;; For distribution policy, see the accompanying file COPYING.
8 ;;;; Filename: conditions.lisp
10 ;;;; Author: Frode Vatvedt Fjeld <frodef@acm.org>
11 ;;;; Created at: Wed Nov 20 15:47:04 2002
13 ;;;; $Id: conditions.lisp,v 1.24 2007/03/12 21:53:40 ffjeld Exp $
15 ;;;;------------------------------------------------------------------
17 (require :muerte
/basic-macros
)
18 (provide :muerte
/conditions
)
22 (defparameter *break-on-signals
* nil
)
24 (defparameter *debugger-function
* nil
)
25 (defvar *debugger-dynamic-context
* nil
)
26 (defparameter *debugger-invoked-stack-frame
* nil
)
27 (defvar *debugger-condition
*)
29 (defmacro define-condition
(name parent-types slot-specs
&rest options
)
31 (defclass ,name
,(or parent-types
'(condition)) ,slot-specs
(:metaclass read-only-class
))
32 ,@(let ((reporter (cadr (assoc :report options
))))
34 `((defmethod print-object ((condition ,name
) stream
)
37 (funcall (function ,reporter
) condition stream
))
42 (defmethod print-object ((c condition
) s
)
45 (define-condition condition
(standard-object)
47 :initarg
:format-control
49 :reader condition-format-control
)
51 :initarg
:format-arguments
53 :reader condition-format-arguments
))
54 (:report
(lambda (condition stream
)
55 (if (or *print-escape
*
56 (not (condition-format-control condition
)))
58 (apply #'format stream
59 (condition-format-control condition
)
60 (condition-format-arguments condition
))))))
62 (define-condition simple-condition
(condition)
64 :reader simple-condition-format-control
)
66 :reader simple-condition-format-arguments
)))
67 (define-condition serious-condition
() ())
68 (define-condition error
(serious-condition) ())
69 (define-condition warning
() ())
70 (define-condition style-warning
() ())
71 (define-condition simple-error
(simple-condition error
) ())
72 (define-condition simple-warning
(simple-condition warning
) ())
74 (define-condition cell-error
(error)
77 :reader cell-error-name
))
78 (:report
(lambda (c s
)
79 (format s
"Error accessing cell ~S."
80 (cell-error-name c
)))))
82 (define-condition undefined-function
(cell-error)
84 (:report
(lambda (c s
)
85 (format s
"Undefined function ~S."
86 (cell-error-name c
)))))
88 (define-condition undefined-function-call
(undefined-function)
91 :reader undefined-function-call-arguments
))
92 (:report
(lambda (c s
)
93 (format s
"Undefined function ~S called with arguments ~:S."
95 (undefined-function-call-arguments c
)))))
97 (define-condition unbound-variable
(cell-error)
99 (:report
(lambda (c s
)
100 (format s
"Unbound variable ~S."
101 (cell-error-name c
)))))
103 (define-condition program-error
(error) ())
105 (define-condition type-error
(error)
107 :initarg
:expected-type
108 :reader type-error-expected-type
)
111 :reader type-error-datum
))
112 (:report
(lambda (c s
)
113 (format s
"The object ~Z `~S' is not of type ~S."
116 (type-error-expected-type c
)))))
118 (define-condition etypecase-error
(type-error)
120 (:report
(lambda (c s
)
121 (format s
"The object '~S' fell through an etypecase where the legal types were ~S."
123 (type-error-expected-type c
)))))
125 (defun etypecase-error (datum expecteds
)
126 (error 'etypecase-error
128 :expected-type
(cons 'or expecteds
)))
130 (define-condition control-error
(error) ())
132 (define-condition throw-error
(control-error)
135 :reader throw-error-tag
))
136 (:report
(lambda (c s
)
137 (format s
"Cannot throw to tag `~S'." (throw-error-tag c
)))))
139 (define-condition wrong-argument-count
(program-error)
142 :reader condition-function
)
144 :initarg
:argument-count
145 :reader condition-argument-count
))
146 (:report
(lambda (c s
)
147 (format s
"Function ~S ~:A received ~D arguments."
148 (funobj-name (condition-function c
))
149 (funobj-lambda-list (condition-function c
))
150 (condition-argument-count c
)))))
152 (define-condition index-out-of-range
(error)
155 :reader condition-index
)
158 :reader condition-range
))
159 (:report
(lambda (c s
)
160 (format s
"Index ~D is beyond range 0-~D."
162 (condition-range c
)))))
164 (define-condition stream-error
(error)
167 :reader stream-error-stream
)))
169 (define-condition end-of-file
(stream-error)
171 (:report
(lambda (c s
)
172 (format s
"End of file encountered on ~W."
173 (stream-error-stream c
)))))
175 (define-condition arithmetic-error
(error)
179 :reader arithmetic-error-operation
)
183 :reader arithmetic-error-operands
)))
185 (define-condition division-by-zero
(arithmetic-error)
187 (:report
(lambda (c s
)
189 (format s
"Division by zero."))))
191 (defun make-condition (type &rest slot-initializations
)
192 (declare (dynamic-extent slot-initializations
))
193 (apply 'make-instance type slot-initializations
))
196 (defun warn (datum &rest arguments
)
197 (declare (dynamic-extent arguments
))
199 ((not (eq t
(get 'clos-bootstrap
'have-bootstrapped
)))
201 (write-string "Warning: ")
202 (apply 'format t datum arguments
)
204 (t (with-simple-restart (muffle-warning "Muffle warning.")
205 (let ((c (signal-simple 'simple-warning datum arguments
))
206 (*standard-output
* *error-output
*))
210 (write-string "Warning: ")
211 (apply 'format t datum arguments
)
213 (t (format t
"~&Warning: ~A"
214 (or c
(coerce-to-condition 'simple-warning datum arguments
)))))))))
217 (defun coerce-to-condition (default-type datum args
)
218 ;; (declare (dynamic-extent args))
223 (apply 'make-condition datum args
))
225 (make-condition default-type
226 :format-control datum
227 :format-arguments
(copy-list args
)))))
229 (defun signal-simple (default-type datum args
)
230 "Signal the condition denoted by a condition designator.
231 Will only make-instance a condition when it is required.
232 Return the condition object, if there was one."
233 (let* ((class (etypecase datum
235 (or (find-class datum nil
)
236 (error "No condition class named ~S." datum
)))
238 (find-class default-type
))
241 (cpl (class-precedence-list class
))
243 (bos-type *break-on-signals
*))
244 (with-simple-restart (continue "Ignore *break-on-signals*.")
245 (let ((*break-on-signals
* nil
)) ; avoid recursive error if *b-o-s* is faulty.
246 (when (typecase bos-type
249 (let ((bos-class (find-class bos-type nil
)))
251 (typep (class-prototype-value class
) bos-type
)
252 (member bos-class cpl
))))
254 (typep (class-prototype-value class
) bos-type
))
255 (t (member bos-type cpl
)))
256 (break "Signalling ~S" datum
))))
257 (macrolet ((invoke-handler (handler)
261 (coerce-to-condition default-type datum args
))))))
262 (let ((*active-condition-handlers
* *active-condition-handlers
*))
263 (do () ((null *active-condition-handlers
*))
264 (let ((handlers (pop *active-condition-handlers
*)))
265 (dolist (handler handlers
)
266 (let ((handler-type (car handler
)))
267 (typecase handler-type
269 (let ((handler-class (find-class handler-type nil
)))
270 (when (if (not handler-class
)
271 (typep (class-prototype-value class
) handler-type
)
273 (setf (car handler
) handler-class
) ; XXX memoize this find-class..
274 (member handler-class cpl
)))
275 (invoke-handler (cdr handler
)))))
277 (when (typep (class-prototype-value class
) handler-type
)
278 (invoke-handler (cdr handler
))))
280 (t (when (member handler-type cpl
)
281 (invoke-handler (cdr handler
)))))))))))
283 (when (typep datum condition
)
286 (defun signal (datum &rest args
)
287 (declare (dynamic-extent args
))
288 (signal-simple 'simple-condition datum args
)
291 (defun invoke-debugger (condition)
292 (when *debugger-hook
*
293 (let ((hook *debugger-hook
*)
294 (*debugger-hook
* nil
))
295 (funcall hook condition hook
)))
297 (unless *debugger-function
*
298 (setf *debugger-function
* #'muerte.init
::my-debugger
))
300 ((not *debugger-function
*)
301 (let ((*never-use-print-object
* t
))
302 (backtrace :spartan t
))
303 (format t
"~&No debugger in *debugger-function*...")
306 (format t
"Trying to continue or abort.")
307 (invoke-restart (or (find-restart 'continue
)
308 (find-restart 'abort
)
309 (format t
"~%Condition for debugger: ~Z" condition
)
310 (format t
"~%No abort restart is active. Halting CPU.")
312 (t (let ((*debugger-invoked-stack-frame
* (stack-frame-uplink nil
(current-stack-frame))))
313 (funcall *debugger-function
* condition
))))
314 (format *debug-io
* "~&Debugger ~@[on ~S ]returned!~%Trying to abort...~%" condition
)
315 (let ((r (find-restart 'abort
)))
318 (format *debug-io
* "~&Aborting failed. Halting CPU.")
321 (defun invoke-debugger-on-designator (&rest designator
)
322 (declare (dynamic-extent designator
))
323 (if (or (eq 'break
(car designator
))
324 (and *error-no-condition-for-debugger
*
325 (symbolp (car designator
)))
326 ;; don't let an error trigger CLOS bootstrapping.
327 (not (eq t
(get 'clos-bootstrap
'have-bootstrapped
))))
328 (invoke-debugger designator
)
329 (invoke-debugger (coerce-to-condition (car designator
)
331 (cddr designator
)))))
333 (defun break (&optional format-control
&rest format-arguments
)
334 (declare (dynamic-extent format-arguments
))
335 (with-simple-restart (continue "Return from break~:[.~;~:*: ~?~]" format-control format-arguments
)
336 ;; (format *debug-io* "~&Break: ~?" format-control format-arguments)
337 (let ((*debugger-hook
* nil
))
338 (apply 'invoke-debugger-on-designator
340 (or format-control
"Break was invoked.")
344 (define-condition newline
() ())