ba5a7f0b400afb4f800a9bb02d09100148fd3a1d
[sbcl.git] / src / code / cold-error.lisp
1 ;;;; miscellaneous stuff that needs to be in the cold load which would
2 ;;;; otherwise be byte-compiled
3
4 ;;;; This software is part of the SBCL system. See the README file for
5 ;;;; more information.
6 ;;;;
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
12
13 (in-package "SB!CONDITIONS")
14
15 (defvar *break-on-signals* nil
16   #!+sb-doc
17   "When (TYPEP condition *BREAK-ON-SIGNALS*) is true, then calls to SIGNAL will
18    enter the debugger prior to signalling that condition.")
19
20 (defun signal (datum &rest arguments)
21   #!+sb-doc
22   "Invokes the signal facility on a condition formed from DATUM and
23    ARGUMENTS. If the condition is not handled, NIL is returned. If
24    (TYPEP condition *BREAK-ON-SIGNALS*) is true, the debugger is invoked
25    before any signalling is done."
26   (let ((condition (coerce-to-condition datum
27                                         arguments
28                                         'simple-condition
29                                         'signal))
30         (*handler-clusters* *handler-clusters*))
31     (let ((old-bos *break-on-signals*)
32           (*break-on-signals* nil))
33       (when (typep condition old-bos)
34         (break "~A~%BREAK was entered because of *BREAK-ON-SIGNALS* (now NIL)."
35                condition)))
36     (loop
37       (unless *handler-clusters* (return))
38       (let ((cluster (pop *handler-clusters*)))
39         (dolist (handler cluster)
40           (when (typep condition (car handler))
41             (funcall (cdr handler) condition)))))
42     nil))
43
44 ;;; COERCE-TO-CONDITION is used in SIGNAL, ERROR, CERROR, WARN, and
45 ;;; INVOKE-DEBUGGER for parsing the hairy argument conventions into a single
46 ;;; argument that's directly usable by all the other routines.
47 (defun coerce-to-condition (datum arguments default-type function-name)
48   (cond ((typep datum 'condition)
49          (if arguments
50              (cerror "Ignore the additional arguments."
51                      'simple-type-error
52                      :datum arguments
53                      :expected-type 'null
54                      :format-control "You may not supply additional arguments ~
55                                      when giving ~S to ~S."
56                      :format-arguments (list datum function-name)))
57          datum)
58         ((symbolp datum) ; roughly, (SUBTYPEP DATUM 'CONDITION)
59          (apply #'make-condition datum arguments))
60         ((or (stringp datum) (functionp datum))
61          (make-condition default-type
62                          :format-control datum
63                          :format-arguments arguments))
64         (t
65          (error 'simple-type-error
66                 :datum datum
67                 :expected-type '(or symbol string)
68                 :format-control "bad argument to ~S: ~S"
69                 :format-arguments (list function-name datum)))))
70
71 (defun error (datum &rest arguments)
72   #!+sb-doc
73   "Invoke the signal facility on a condition formed from datum and arguments.
74    If the condition is not handled, the debugger is invoked."
75   (/show0 "entering ERROR")
76   #!+sb-show
77   (unless *cold-init-complete-p*
78     (/show0 "ERROR in cold init, arguments=..")
79     #!+sb-show (dolist (argument arguments)
80                  (sb!impl::cold-print argument)))
81   (sb!kernel:infinite-error-protect
82     (let ((condition (coerce-to-condition datum arguments
83                                           'simple-error 'error))
84           ;; FIXME: Why is *STACK-TOP-HINT* in SB-DEBUG instead of SB-DI?
85           ;; SB-DEBUG should probably be only for true interface stuff.
86           (sb!debug:*stack-top-hint* sb!debug:*stack-top-hint*))
87       (unless (and (condition-function-name condition)
88                    sb!debug:*stack-top-hint*)
89         (multiple-value-bind (name frame) (sb!kernel:find-caller-name)
90           (unless (condition-function-name condition)
91             (setf (condition-function-name condition) name))
92           (unless sb!debug:*stack-top-hint*
93             (setf sb!debug:*stack-top-hint* frame))))
94       (let ((sb!debug:*stack-top-hint* nil))
95         (signal condition))
96       (invoke-debugger condition))))
97
98 (defun cerror (continue-string datum &rest arguments)
99   (sb!kernel:infinite-error-protect
100     (with-simple-restart
101         (continue "~A" (apply #'format nil continue-string arguments))
102       (let ((condition (if (typep datum 'condition)
103                            datum
104                            (coerce-to-condition datum
105                                                 arguments
106                                                 'simple-error
107                                                 'error)))
108             (sb!debug:*stack-top-hint* sb!debug:*stack-top-hint*))
109         (unless (and (condition-function-name condition)
110                      sb!debug:*stack-top-hint*)
111           (multiple-value-bind (name frame) (sb!kernel:find-caller-name)
112             (unless (condition-function-name condition)
113               (setf (condition-function-name condition) name))
114             (unless sb!debug:*stack-top-hint*
115               (setf sb!debug:*stack-top-hint* frame))))
116         (with-condition-restarts condition (list (find-restart 'continue))
117           (let ((sb!debug:*stack-top-hint* nil))
118             (signal condition))
119           (invoke-debugger condition)))))
120   nil)
121
122 (defun break (&optional (datum "break") &rest arguments)
123   #!+sb-doc
124   "Print a message and invoke the debugger without allowing any possibility
125    of condition handling occurring."
126   (sb!kernel:infinite-error-protect
127     (with-simple-restart (continue "Return from BREAK.")
128       (let ((sb!debug:*stack-top-hint*
129              (or sb!debug:*stack-top-hint*
130                  (nth-value 1 (sb!kernel:find-caller-name)))))
131         (invoke-debugger
132          (coerce-to-condition datum arguments 'simple-condition 'break)))))
133   nil)
134
135 (defun warn (datum &rest arguments)
136   #!+sb-doc
137   "Warn about a situation by signalling a condition formed by DATUM and
138    ARGUMENTS. While the condition is being signaled, a MUFFLE-WARNING restart
139    exists that causes WARN to immediately return NIL."
140   (/noshow0 "entering WARN")
141   ;; KLUDGE: The current cold load initialization logic causes several calls
142   ;; to WARN, so we need to be able to handle them without dying. (And calling
143   ;; FORMAT or even PRINC in cold load is a good way to die.) Of course, the
144   ;; ideal would be to clean up cold load so that it doesn't call WARN..
145   ;; -- WHN 19991009
146   (if (not *cold-init-complete-p*)
147       (progn
148         (/show0 "ignoring WARN in cold init, arguments=..")
149         #!+sb-show (dolist (argument arguments)
150                      (sb!impl::cold-print argument)))
151       (sb!kernel:infinite-error-protect
152        (let ((condition (coerce-to-condition datum arguments
153                                              'simple-warning 'warn)))
154          (check-type condition warning "a warning condition")
155          (restart-case (signal condition)
156            (muffle-warning ()
157              :report "Skip warning."
158              (return-from warn nil)))
159          (let ((badness (etypecase condition
160                           (style-warning 'style-warning)
161                           (warning 'warning))))
162            (format *error-output*
163                    "~&~@<~S: ~3i~:_~A~:>~%"
164                    badness
165                    condition)))))
166   nil)