1 /*
2 * error.c - error handling
3 *
4 * Copyright (c) 2000-2020 Shiro Kawai <shiro@acm.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the authors nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #define LIBGAUCHE_BODY
35 #include "gauche.h"
36 #include "gauche/class.h"
37 #include "gauche/exception.h"
38 #include "gauche/vm.h"
39 #include "gauche/priv/builtin-syms.h"
40
41 #include <errno.h>
42 #include <string.h>
43 #include <ctype.h>
44
45 static ScmObj condition_allocate(ScmClass *klass, ScmObj initargs);
46 static ScmObj message_allocate(ScmClass *klass, ScmObj initargs);
47 static ScmObj syserror_allocate(ScmClass *klass, ScmObj initargs);
48 static ScmObj sigerror_allocate(ScmClass *klass, ScmObj initargs);
49 static ScmObj readerror_allocate(ScmClass *klass, ScmObj initargs);
50 static ScmObj porterror_allocate(ScmClass *klass, ScmObj initargs);
51 static ScmObj compound_allocate(ScmClass *klass, ScmObj initargs);
52
53 /* Setting up CPL is a bit tricky, since we have multiple
54 inheritance case. */
55
56 #define CONDITION_CPL \
57 SCM_CLASS_STATIC_PTR(Scm_ConditionClass), \
58 SCM_CLASS_STATIC_PTR(Scm_TopClass)
59
60 #define MESSAGE_SERIOUS_CPL \
61 SCM_CLASS_STATIC_PTR(Scm_MessageConditionClass), \
62 SCM_CLASS_STATIC_PTR(Scm_SeriousConditionClass), \
63 CONDITION_CPL
64
65 #define ERROR_CPL \
66 SCM_CLASS_STATIC_PTR(Scm_ErrorClass), \
67 MESSAGE_SERIOUS_CPL
68
69 /*-----------------------------------------------------------
70 * Base conditions
71 */
72 static ScmClass *condition_cpl[] = {
73 CONDITION_CPL,
74 NULL
75 };
76
77 SCM_DEFINE_BASE_CLASS(Scm_ConditionClass, ScmInstance,
78 NULL, NULL, NULL,
79 condition_allocate, SCM_CLASS_DEFAULT_CPL);
80 SCM_DEFINE_BASE_CLASS(Scm_MessageConditionClass, ScmMessageCondition,
81 Scm_MessageConditionPrint, NULL, NULL,
82 message_allocate, condition_cpl);
83 SCM_DEFINE_BASE_CLASS(Scm_SeriousConditionClass, ScmSeriousCondition,
84 NULL, NULL, NULL,
85 condition_allocate, condition_cpl);
86 SCM_DEFINE_BASE_CLASS(Scm_MixinConditionClass, ScmCondition,
87 NULL, NULL, NULL,
88 condition_allocate, condition_cpl);
89
condition_allocate(ScmClass * klass,ScmObj initargs SCM_UNUSED)90 static ScmObj condition_allocate(ScmClass *klass, ScmObj initargs SCM_UNUSED)
91 {
92 return SCM_OBJ(SCM_NEW_INSTANCE(ScmCondition, klass));
93 }
94
95 /* We expose this, for other condition subclasses may share this. */
Scm_MessageConditionPrint(ScmObj obj,ScmPort * port,ScmWriteContext * ctx SCM_UNUSED)96 void Scm_MessageConditionPrint(ScmObj obj, ScmPort *port,
97 ScmWriteContext *ctx SCM_UNUSED)
98 {
99 ScmClass *k = Scm_ClassOf(obj);
100 Scm_Printf(port, "#<%A \"%30.1A\">",
101 Scm_ShortClassName(k),
102 SCM_ERROR_MESSAGE(obj));
103 }
104
message_allocate(ScmClass * klass,ScmObj initargs SCM_UNUSED)105 static ScmObj message_allocate(ScmClass *klass, ScmObj initargs SCM_UNUSED)
106 {
107 ScmError *e = SCM_NEW_INSTANCE(ScmError, klass);
108 e->message = SCM_FALSE; /* would be set by initialize */
109 return SCM_OBJ(e);
110 }
111
112 /* See comment on gauche/exception.h about hack in 'message' slot.
113 TRANSIENT: Remove this hack on 1.0 release. */
message_get(ScmMessageCondition * obj)114 static ScmObj message_get(ScmMessageCondition *obj)
115 {
116 ScmObj msglist = obj->message;
117 if (SCM_PAIRP(msglist)) return SCM_CAR(msglist);
118 else return msglist;
119 }
120
message_set(ScmMessageCondition * obj,ScmObj val)121 static void message_set(ScmMessageCondition *obj, ScmObj val)
122 {
123 ScmObj msglist = obj->message;
124 if (SCM_PAIRP(msglist)) SCM_SET_CAR_UNCHECKED(msglist, val);
125 else SCM_MESSAGE_CONDITION(obj)->message = SCM_LIST2(val, val);
126 }
127
message_prefix_get(ScmMessageCondition * obj)128 static ScmObj message_prefix_get(ScmMessageCondition *obj)
129 {
130 ScmObj msglist = obj->message;
131 if (SCM_PAIRP(msglist) && SCM_PAIRP(SCM_CDR(msglist))) {
132 return SCM_CADR(msglist);
133 } else {
134 return msglist;
135 }
136 }
137
message_prefix_set(ScmMessageCondition * obj,ScmObj val)138 static void message_prefix_set(ScmMessageCondition *obj, ScmObj val)
139 {
140 ScmObj msglist = obj->message;
141 if (SCM_PAIRP(msglist) && SCM_PAIRP(SCM_CDR(msglist))) {
142 SCM_SET_CAR_UNCHECKED(SCM_CDR(msglist), val);
143 } else {
144 obj->message = SCM_LIST2(msglist, val);
145 }
146 }
147
message_args_get(ScmMessageCondition * obj)148 static ScmObj message_args_get(ScmMessageCondition *obj)
149 {
150 ScmObj msglist = obj->message;
151 if (SCM_PAIRP(msglist) && SCM_PAIRP(SCM_CDR(msglist))) {
152 return SCM_CDDR(msglist);
153 } else {
154 return SCM_NIL;
155 }
156 }
157
message_args_set(ScmMessageCondition * obj,ScmObj val)158 static void message_args_set(ScmMessageCondition *obj, ScmObj val)
159 {
160 ScmObj msglist = obj->message;
161 if (SCM_PAIRP(msglist) && SCM_PAIRP(SCM_CDR(msglist))) {
162 SCM_SET_CDR_UNCHECKED(SCM_CDR(msglist), val);
163 } else {
164 obj->message = Scm_Cons(msglist, Scm_Cons(msglist, val));
165 }
166 }
167
168 static ScmClassStaticSlotSpec message_slots[] = {
169 SCM_CLASS_SLOT_SPEC("message", message_get, message_set),
170 SCM_CLASS_SLOT_SPEC("message-prefix", message_prefix_get, message_prefix_set),
171 SCM_CLASS_SLOT_SPEC("message-args", message_args_get, message_args_set),
172 SCM_CLASS_SLOT_SPEC_END()
173 };
174
175 /*------------------------------------------------------------
176 * Errors
177 */
178
179 static ScmClass *error_cpl[] = {
180 ERROR_CPL,
181 NULL
182 };
183
184 static ScmClass *porterror_cpl[] = {
185 SCM_CLASS_STATIC_PTR(Scm_PortErrorClass),
186 SCM_CLASS_STATIC_PTR(Scm_IOErrorClass),
187 ERROR_CPL,
188 NULL
189 };
190
191 static ScmClass *decoding_error_cpl[] = {
192 SCM_CLASS_STATIC_PTR(Scm_IOReadErrorClass),
193 SCM_CLASS_STATIC_PTR(Scm_PortErrorClass),
194 SCM_CLASS_STATIC_PTR(Scm_IOErrorClass),
195 ERROR_CPL,
196 NULL
197 };
198
199 static ScmClass *encoding_error_cpl[] = {
200 SCM_CLASS_STATIC_PTR(Scm_IOWriteErrorClass),
201 SCM_CLASS_STATIC_PTR(Scm_PortErrorClass),
202 SCM_CLASS_STATIC_PTR(Scm_IOErrorClass),
203 ERROR_CPL,
204 NULL
205 };
206
207 SCM_DEFINE_BASE_CLASS(Scm_ErrorClass, ScmError,
208 Scm_MessageConditionPrint, NULL, NULL,
209 message_allocate, error_cpl+1);
210 SCM_DEFINE_BASE_CLASS(Scm_SystemErrorClass, ScmSystemError,
211 Scm_MessageConditionPrint, NULL, NULL,
212 syserror_allocate, error_cpl);
213 SCM_DEFINE_BASE_CLASS(Scm_UnhandledSignalErrorClass, ScmUnhandledSignalError,
214 Scm_MessageConditionPrint, NULL, NULL,
215 sigerror_allocate, error_cpl);
216 SCM_DEFINE_BASE_CLASS(Scm_ReadErrorClass, ScmReadError,
217 Scm_MessageConditionPrint, NULL, NULL,
218 readerror_allocate, error_cpl);
219 SCM_DEFINE_BASE_CLASS(Scm_IOErrorClass, ScmIOError,
220 Scm_MessageConditionPrint, NULL, NULL,
221 message_allocate, error_cpl);
222 SCM_DEFINE_BASE_CLASS(Scm_PortErrorClass, ScmPortError,
223 Scm_MessageConditionPrint, NULL, NULL,
224 porterror_allocate, porterror_cpl+1);
225 SCM_DEFINE_BASE_CLASS(Scm_IOReadErrorClass, ScmIOReadError,
226 Scm_MessageConditionPrint, NULL, NULL,
227 porterror_allocate, porterror_cpl);
228 SCM_DEFINE_BASE_CLASS(Scm_IOWriteErrorClass, ScmIOWriteError,
229 Scm_MessageConditionPrint, NULL, NULL,
230 porterror_allocate, porterror_cpl);
231 SCM_DEFINE_BASE_CLASS(Scm_IOClosedErrorClass, ScmIOClosedError,
232 Scm_MessageConditionPrint, NULL, NULL,
233 porterror_allocate, porterror_cpl);
234 SCM_DEFINE_BASE_CLASS(Scm_IOUnitErrorClass, ScmIOUnitError,
235 Scm_MessageConditionPrint, NULL, NULL,
236 porterror_allocate, porterror_cpl);
237 SCM_DEFINE_BASE_CLASS(Scm_IODecodingErrorClass, ScmIODecodingError,
238 Scm_MessageConditionPrint, NULL, NULL,
239 porterror_allocate, decoding_error_cpl);
240 SCM_DEFINE_BASE_CLASS(Scm_IOEncodingErrorClass, ScmIOEncodingError,
241 Scm_MessageConditionPrint, NULL, NULL,
242 porterror_allocate, encoding_error_cpl);
243 SCM_DEFINE_BASE_CLASS(Scm_IOInvalidPositionErrorClass, ScmIOInvalidPositionError,
244 Scm_MessageConditionPrint, NULL, NULL,
245 porterror_allocate, porterror_cpl);
246
syserror_allocate(ScmClass * klass,ScmObj initargs SCM_UNUSED)247 static ScmObj syserror_allocate(ScmClass *klass, ScmObj initargs SCM_UNUSED)
248 {
249 ScmSystemError *e = SCM_NEW_INSTANCE(ScmSystemError, klass);
250 e->common.message = SCM_FALSE; /* set by initialize */
251 e->error_number = 0; /* set by initialize */
252 return SCM_OBJ(e);
253 }
254
sigerror_allocate(ScmClass * klass,ScmObj initargs SCM_UNUSED)255 static ScmObj sigerror_allocate(ScmClass *klass, ScmObj initargs SCM_UNUSED)
256 {
257 ScmUnhandledSignalError *e = SCM_NEW_INSTANCE(ScmUnhandledSignalError,
258 klass);
259 e->common.message = SCM_FALSE; /* set by initialize */
260 e->signal = 0; /* set by initialize */
261 return SCM_OBJ(e);
262 }
263
readerror_allocate(ScmClass * klass,ScmObj initargs SCM_UNUSED)264 static ScmObj readerror_allocate(ScmClass *klass, ScmObj initargs SCM_UNUSED)
265 {
266 ScmReadError *e = SCM_NEW_INSTANCE(ScmReadError, klass);
267 e->common.message = SCM_FALSE; /* set by initialize */
268 e->port = NULL; /* set by initialize */
269 e->line = -1; /* set by initialize */
270 return SCM_OBJ(e);
271 }
272
porterror_allocate(ScmClass * klass,ScmObj initargs SCM_UNUSED)273 static ScmObj porterror_allocate(ScmClass *klass, ScmObj initargs SCM_UNUSED)
274 {
275 ScmPortError *e = SCM_NEW_INSTANCE(ScmPortError, klass);
276 e->common.message = SCM_FALSE; /* set by initialize */
277 e->port = NULL; /* set by initialize */
278 e->auxinfo = SCM_NIL; /* set by initialize */
279 return SCM_OBJ(e);
280 }
281
syserror_number_get(ScmSystemError * obj)282 static ScmObj syserror_number_get(ScmSystemError *obj)
283 {
284 return SCM_MAKE_INT(obj->error_number);
285 }
286
syserror_number_set(ScmSystemError * obj,ScmObj val)287 static void syserror_number_set(ScmSystemError *obj, ScmObj val)
288 {
289 if (!SCM_INTP(val)) {
290 Scm_Error("small integer required, but got %S", val);
291 }
292 obj->error_number = SCM_INT_VALUE(val);
293 }
294
sigerror_signal_get(ScmUnhandledSignalError * obj)295 static ScmObj sigerror_signal_get(ScmUnhandledSignalError *obj)
296 {
297 return SCM_MAKE_INT(obj->signal);
298 }
299
sigerror_signal_set(ScmUnhandledSignalError * obj,ScmObj val)300 static void sigerror_signal_set(ScmUnhandledSignalError *obj, ScmObj val)
301 {
302 if (!SCM_INTP(val)) {
303 Scm_Error("small integer required, but got %S", val);
304 }
305 obj->signal = SCM_INT_VALUE(val);
306 }
307
readerror_port_get(ScmReadError * obj)308 static ScmObj readerror_port_get(ScmReadError *obj)
309 {
310 if (obj->port) return SCM_OBJ(obj->port);
311 else return SCM_FALSE;
312 }
313
readerror_port_set(ScmReadError * obj,ScmObj val)314 static void readerror_port_set(ScmReadError *obj, ScmObj val)
315 {
316 if (SCM_IPORTP(val)) {
317 obj->port = SCM_PORT(val);
318 }
319 else if (SCM_FALSEP(val)) {
320 obj->port = NULL;
321 }
322 else {
323 Scm_Error("input port or #f required, but got %S", val);
324 }
325 }
326
readerror_line_get(ScmReadError * obj)327 static ScmObj readerror_line_get(ScmReadError *obj)
328 {
329 return SCM_MAKE_INT(obj->line);
330 }
331
readerror_line_set(ScmReadError * obj,ScmObj val)332 static void readerror_line_set(ScmReadError *obj, ScmObj val)
333 {
334 if (!SCM_INTP(val)){
335 Scm_Error("small integer required, but got %S", val);
336 }
337 obj->line = SCM_INT_VALUE(val);
338 }
339
readerror_dummy_get(ScmReadError * obj SCM_UNUSED)340 static ScmObj readerror_dummy_get(ScmReadError *obj SCM_UNUSED)
341 {
342 return SCM_FALSE;
343 }
344
readerror_dummy_set(ScmReadError * obj SCM_UNUSED,ScmObj val SCM_UNUSED)345 static void readerror_dummy_set(ScmReadError *obj SCM_UNUSED,
346 ScmObj val SCM_UNUSED)
347 {
348 /* nothing */
349 }
350
porterror_port_get(ScmPortError * obj)351 static ScmObj porterror_port_get(ScmPortError *obj)
352 {
353 return obj->port? SCM_OBJ(obj->port) : SCM_FALSE;
354 }
355
porterror_port_set(ScmPortError * obj,ScmObj val)356 static void porterror_port_set(ScmPortError *obj, ScmObj val)
357 {
358 if (!SCM_PORTP(val) && !SCM_FALSEP(val)) {
359 Scm_Error("port or #f required, but got %S", val);
360 }
361 obj->port = SCM_FALSEP(val)? NULL : SCM_PORT(val);
362 }
363
porterror_auxinfo_getter(ScmPortError * obj,ScmObj key)364 static ScmObj porterror_auxinfo_getter(ScmPortError *obj, ScmObj key)
365 {
366 ScmObj p = Scm_Assq(key, obj->auxinfo);
367 if (SCM_PAIRP(p)) return SCM_CDR(p);
368 return SCM_FALSE;
369 }
370
porterror_auxinfo_setter(ScmPortError * obj,ScmObj key,ScmObj val)371 static void porterror_auxinfo_setter(ScmPortError *obj, ScmObj key, ScmObj val)
372 {
373 ScmObj p = Scm_Assq(key, obj->auxinfo);
374 if (SCM_PAIRP(p)) SCM_SET_CDR(p, val);
375 else obj->auxinfo = Scm_Acons(key, val, obj->auxinfo);
376 }
377
378 static ScmObj sym_offending_char; /* 'offending-char */
379
porterror_offending_char_get(ScmPortError * obj)380 static ScmObj porterror_offending_char_get(ScmPortError *obj)
381 {
382 return porterror_auxinfo_getter(obj, sym_offending_char);
383 }
384
porterror_offending_char_set(ScmPortError * obj,ScmObj val)385 static void porterror_offending_char_set(ScmPortError *obj, ScmObj val)
386 {
387 porterror_auxinfo_setter(obj, sym_offending_char, val);
388 }
389
390 static ScmObj sym_position; /* 'position */
391
porterror_position_get(ScmPortError * obj)392 static ScmObj porterror_position_get(ScmPortError *obj)
393 {
394 return porterror_auxinfo_getter(obj, sym_position);
395 }
396
porterror_position_set(ScmPortError * obj,ScmObj val)397 static void porterror_position_set(ScmPortError *obj, ScmObj val)
398 {
399 porterror_auxinfo_setter(obj, sym_position, val);
400 }
401
402 static ScmClassStaticSlotSpec syserror_slots[] = {
403 SCM_CLASS_SLOT_SPEC("errno", syserror_number_get, syserror_number_set),
404 SCM_CLASS_SLOT_SPEC_END()
405 };
406
407 static ScmClassStaticSlotSpec sigerror_slots[] = {
408 SCM_CLASS_SLOT_SPEC("signal", sigerror_signal_get, sigerror_signal_set),
409 SCM_CLASS_SLOT_SPEC_END()
410 };
411
412 static ScmClassStaticSlotSpec readerror_slots[] = {
413 SCM_CLASS_SLOT_SPEC("port", readerror_port_get, readerror_port_set),
414 SCM_CLASS_SLOT_SPEC("line", readerror_line_get, readerror_line_set),
415 SCM_CLASS_SLOT_SPEC("column", readerror_dummy_get, readerror_dummy_set),
416 SCM_CLASS_SLOT_SPEC("position", readerror_dummy_get, readerror_dummy_set),
417 SCM_CLASS_SLOT_SPEC("span", readerror_dummy_get, readerror_dummy_set),
418 SCM_CLASS_SLOT_SPEC_END()
419 };
420
421 static ScmClassStaticSlotSpec porterror_slots[] = {
422 SCM_CLASS_SLOT_SPEC("port", porterror_port_get, porterror_port_set),
423 SCM_CLASS_SLOT_SPEC_END()
424 };
425
426 static ScmClassStaticSlotSpec encodingerror_slots[] = {
427 SCM_CLASS_SLOT_SPEC("port", porterror_port_get, porterror_port_set),
428 SCM_CLASS_SLOT_SPEC("offending-char",
429 porterror_offending_char_get,
430 porterror_offending_char_set),
431 SCM_CLASS_SLOT_SPEC_END()
432 };
433
434 static ScmClassStaticSlotSpec invalidpositionerror_slots[] = {
435 SCM_CLASS_SLOT_SPEC("port", porterror_port_get, porterror_port_set),
436 SCM_CLASS_SLOT_SPEC("position",
437 porterror_position_get,
438 porterror_position_set),
439 SCM_CLASS_SLOT_SPEC_END()
440 };
441
442
443 /*------------------------------------------------------------
444 * Compound conditions
445 */
446
447 static ScmClass *compound_cpl[] = {
448 SCM_CLASS_STATIC_PTR(Scm_CompoundConditionClass),
449 SCM_CLASS_STATIC_PTR(Scm_SeriousConditionClass),
450 CONDITION_CPL,
451 NULL
452 };
453
compound_print(ScmObj obj,ScmPort * port,ScmWriteContext * ctx SCM_UNUSED)454 static void compound_print(ScmObj obj, ScmPort *port,
455 ScmWriteContext *ctx SCM_UNUSED)
456 {
457 ScmClass *k = Scm_ClassOf(obj);
458 Scm_Printf(port, "#<%A", Scm_ShortClassName(k));
459 ScmCompoundCondition *c = SCM_COMPOUND_CONDITION(obj);
460 ScmObj cp;
461 SCM_FOR_EACH(cp, c->conditions) {
462 Scm_Printf(port, " %A", SCM_CAR(cp));
463 }
464 Scm_Printf(port, ">");
465 }
466
467 SCM_DEFINE_BASE_CLASS(Scm_CompoundConditionClass, ScmCompoundCondition,
468 compound_print, NULL, NULL,
469 compound_allocate, compound_cpl+2);
470 SCM_DEFINE_BASE_CLASS(Scm_SeriousCompoundConditionClass, ScmCompoundCondition,
471 compound_print, NULL, NULL,
472 compound_allocate, compound_cpl);
473
compound_allocate(ScmClass * klass,ScmObj initargs SCM_UNUSED)474 static ScmObj compound_allocate(ScmClass *klass, ScmObj initargs SCM_UNUSED)
475 {
476 ScmCompoundCondition *e = SCM_NEW_INSTANCE(ScmCompoundCondition, klass);
477 e->conditions = SCM_NIL;
478 return SCM_OBJ(e);
479 }
480
Scm_MakeCompoundCondition(ScmObj conditions)481 ScmObj Scm_MakeCompoundCondition(ScmObj conditions)
482 {
483 ScmObj h = SCM_NIL, t = SCM_NIL;
484 int serious = FALSE;
485 int nconds = Scm_Length(conditions);
486
487 /* some boundary cases */
488 if (nconds < 0) {
489 Scm_Error("Scm_MakeCompoundCondition: list required, but got %S",
490 conditions);
491 }
492 if (nconds == 0) {
493 return compound_allocate(SCM_CLASS_COMPOUND_CONDITION, SCM_NIL);
494 }
495 if (nconds == 1) {
496 if (!SCM_CONDITIONP(SCM_CAR(conditions))) {
497 Scm_Error("make-compound-condition: given non-condition object: %S", SCM_CAR(conditions));
498 }
499 return SCM_CAR(conditions);
500 }
501
502 /* collect conditions and creates compound one */
503 ScmObj cp;
504 SCM_FOR_EACH(cp, conditions) {
505 ScmObj c = SCM_CAR(cp);
506 if (!SCM_CONDITIONP(c)) {
507 Scm_Error("make-compound-condition: given non-condition object: %S", SCM_CAR(cp));
508 }
509 if (SCM_SERIOUS_CONDITION_P(c)) {
510 serious = TRUE;
511 }
512
513 if (SCM_COMPOUND_CONDITION_P(c)) {
514 ScmCompoundCondition *cc = SCM_COMPOUND_CONDITION(c);
515 SCM_APPEND(h, t, cc->conditions);
516 } else {
517 SCM_APPEND1(h, t, c);
518 }
519 }
520 ScmObj cond = compound_allocate((serious?
521 SCM_CLASS_COMPOUND_CONDITION :
522 SCM_CLASS_SERIOUS_COMPOUND_CONDITION),
523 SCM_NIL);
524 SCM_COMPOUND_CONDITION(cond)->conditions = h;
525 return cond;
526 }
527
528 /* Extract condition of type TYPE from a compound condition CONDITION.
529 The returned condition may be of subtype of TYPE.
530 CONDITION may be simple condition; in that case, CONDITION itself
531 is returned iff condition is of a subtype of TYPE.
532 This isn't the same as `extract-condition' of SRFI-35, which always
533 returns a condition of the specified type; it also has different
534 rule to refer to the slots.
535 */
Scm_ExtractSimpleCondition(ScmObj condition,ScmClass * type)536 ScmObj Scm_ExtractSimpleCondition(ScmObj condition, ScmClass *type)
537 {
538 ScmObj cs = (SCM_COMPOUND_CONDITION_P(condition)
539 ? SCM_COMPOUND_CONDITION(condition)->conditions
540 : SCM_LIST1(condition));
541 ScmObj cp;
542 SCM_FOR_EACH(cp, cs) {
543 if (SCM_ISA(SCM_CAR(cp), type)) return SCM_CAR(cp);
544 }
545 return SCM_FALSE;
546 }
547
conditions_get(ScmCompoundCondition * obj)548 static ScmObj conditions_get(ScmCompoundCondition *obj)
549 {
550 return obj->conditions;
551 }
552
conditions_set(ScmCompoundCondition * obj,ScmObj conds)553 static void conditions_set(ScmCompoundCondition *obj, ScmObj conds)
554 {
555 ScmObj cp;
556 SCM_FOR_EACH(cp, conds) {
557 if (!SCM_CONDITIONP(SCM_CAR(cp))) goto err;
558 }
559 if (!SCM_NULLP(cp)) {
560 err:
561 Scm_Error("conditions slot of a compound condition must be a list of conditions, but got %S", conds);
562 }
563 obj->conditions = conds;
564 }
565
566 static ScmClassStaticSlotSpec compound_slots[] = {
567 SCM_CLASS_SLOT_SPEC("%conditions", conditions_get, conditions_set),
568 SCM_CLASS_SLOT_SPEC_END()
569 };
570
571
572 /*
573 * C-level Constructors & generic API
574 */
575
576 /* actual class structure of thread exceptions are in ext/threads */
Scm_MakeThreadException(ScmClass * klass,ScmVM * thread)577 ScmObj Scm_MakeThreadException(ScmClass *klass, ScmVM *thread)
578 {
579 ScmThreadException *e = SCM_NEW(ScmThreadException);
580 SCM_SET_CLASS(e, klass);
581 e->thread = thread;
582 e->data = SCM_UNDEFINED;
583 return SCM_OBJ(e);
584 }
585
Scm_MakeError(ScmObj message)586 ScmObj Scm_MakeError(ScmObj message)
587 {
588 ScmError *e = SCM_ERROR(message_allocate(SCM_CLASS_ERROR, SCM_NIL));
589 e->message = SCM_LIST2(message, message);
590 return SCM_OBJ(e);
591 }
592
Scm_MakeSystemError(ScmObj message,int en)593 ScmObj Scm_MakeSystemError(ScmObj message, int en)
594 {
595 ScmSystemError *e =
596 SCM_SYSTEM_ERROR(syserror_allocate(SCM_CLASS_SYSTEM_ERROR, SCM_NIL));
597 e->common.message = SCM_LIST2(message, message);
598 e->error_number = en;
599 return SCM_OBJ(e);
600 }
601
Scm_MakeReadError(ScmObj message,ScmPort * port,int line)602 ScmObj Scm_MakeReadError(ScmObj message, ScmPort *port, int line)
603 {
604 ScmReadError *e =
605 SCM_READ_ERROR(readerror_allocate(SCM_CLASS_READ_ERROR, SCM_NIL));
606 e->common.message = SCM_LIST2(message, message);
607 e->port = port;
608 e->line = line;
609 return SCM_OBJ(e);
610 }
611
Scm_ConditionHasType(ScmObj c,ScmObj k)612 int Scm_ConditionHasType(ScmObj c, ScmObj k)
613 {
614 if (!SCM_CONDITIONP(c)) return FALSE;
615 if (!SCM_CLASSP(k)) return FALSE;
616 if (!SCM_COMPOUND_CONDITION_P(c)) return SCM_ISA(c, SCM_CLASS(k));
617
618 ScmObj cp;
619 SCM_FOR_EACH(cp, SCM_COMPOUND_CONDITION(c)->conditions) {
620 if (SCM_ISA(SCM_CAR(cp), SCM_CLASS(k))) return TRUE;
621 }
622 return FALSE;
623 }
624
Scm_ConditionMessage(ScmObj c)625 ScmObj Scm_ConditionMessage(ScmObj c)
626 {
627 if (SCM_MESSAGE_CONDITION_P(c)) {
628 return message_get(SCM_MESSAGE_CONDITION(c));
629 } else if (SCM_COMPOUND_CONDITION_P(c)) {
630 ScmObj cp;
631 SCM_FOR_EACH(cp, SCM_COMPOUND_CONDITION(c)->conditions) {
632 if (SCM_MESSAGE_CONDITION_P(SCM_CAR(cp))) {
633 return message_get(SCM_MESSAGE_CONDITION(SCM_CAR(cp)));
634 }
635 }
636 }
637 return SCM_FALSE;
638 }
639
640 /* Returns a ScmString representiong the 'type name' of the condition,
641 suitable for the error message. Because of personal preference
642 and backward compatibility, I upcase the class name of the condition
643 sans brackets. If it is a composite condition, the component's typenames
644 are joind with commas, excluding mixin conditions.
645 */
Scm_ConditionTypeName(ScmObj c)646 ScmObj Scm_ConditionTypeName(ScmObj c)
647 {
648 ScmObj sname;
649 static SCM_DEFINE_STRING_CONST(cond_name_delim, ",", 1, 1);
650
651 /* just a safety net */
652 if (!SCM_CONDITIONP(c)) return SCM_MAKE_STR("(not a condition)");
653
654 if (!SCM_COMPOUND_CONDITION_P(c)) {
655 sname = Scm_ShortClassName(Scm_ClassOf(c));
656 } else {
657 ScmObj h = SCM_NIL, t = SCM_NIL, cp;
658 SCM_FOR_EACH(cp, SCM_COMPOUND_CONDITION(c)->conditions) {
659 ScmObj cc = SCM_CAR(cp);
660 if (SCM_MIXIN_CONDITION_P(cc)) continue;
661 SCM_APPEND1(h, t, Scm_ShortClassName(Scm_ClassOf(cc)));
662 }
663 if (SCM_NULLP(h)) {
664 /* not usual, but tolerate */
665 sname = Scm_ShortClassName(Scm_ClassOf(c));
666 } else {
667 sname = Scm_StringJoin(h, &cond_name_delim, SCM_STRING_JOIN_INFIX);
668 }
669 }
670
671 ScmDString ds;
672 Scm_DStringInit(&ds);
673 ScmObj p = Scm_MakeInputStringPort(SCM_STRING(sname), TRUE);
674 int ch;
675 while ((ch = Scm_Getc(SCM_PORT(p))) != EOF) {
676 Scm_DStringPutc(&ds, Scm_CharUpcase(ch));
677 }
678 return Scm_DStringGet(&ds, 0);
679 }
680
681 /*================================================================
682 * Error handling
683 *
684 * The interaction with dynamic environment of VM is handled by
685 * Scm_VMThrowException() in vm.c. These routines provide
686 * application interface.
687 *
688 * Note on Windows system error: Windows may return error code
689 * in two different ways; GetLastError for Windows API, and errno
690 * for posix-compatibility calls. When Scm_SysError is called
691 * we don't know which error code to look at for sure. As a
692 * convention, we always clear both error code after Scm_SysError
693 * and assumes whichever non-zero code indicates the actual error.
694 * To map to integer error code, we reverse the sign of Windows
695 * error code (Windows error code reserves full 32bit, but they don't
696 * seem to use over 2^31 for the time being).
697 */
698
699 /* Double fault check
700 * In order to aviod infinite loop when error throwing routine
701 * throws an error, we use vm flag SCM_ERROR_BEING_HANDLED to
702 * check that. Ideally a common single API should handle it,
703 * but for the time being, we add the check at the beginning
704 * of Scm_*Error APIs.
705 * The SCM_ERROR_BEING_HANDLED flag is cleared in Scm_VMThrowException().
706 */
707 #define SCM_ERROR_DOUBLE_FAULT_CHECK(vm, msg) \
708 do { \
709 if (SCM_VM_RUNTIME_FLAG_IS_SET(vm, SCM_ERROR_BEING_HANDLED)) { \
710 ScmDString ds; \
711 Scm_DStringInit(&ds); \
712 Scm_DStringPutz(&ds, "Error occurred in error handler (", -1); \
713 Scm_DStringPutz(&ds, msg, -1); \
714 Scm_DStringPutz(&ds, ")", -1); \
715 ScmObj e = Scm_MakeError(Scm_DStringGet(&ds, 0)); \
716 Scm_VMThrowException(vm, e, SCM_RAISE_NON_CONTINUABLE); \
717 } \
718 SCM_VM_RUNTIME_FLAG_SET(vm, SCM_ERROR_BEING_HANDLED); \
719 } while (0)
720
721 /* Common part to format error message passed as varargs.
722 * ostr must be declared as ScmObj, and msg must be the last
723 * arg of function before '...'.
724 */
725 #define SCM_ERROR_MESSAGE_FORMAT(ostr, msg) \
726 do { \
727 ostr = Scm_MakeOutputStringPort(TRUE); \
728 va_list args__; \
729 va_start(args__, msg); \
730 Scm_Vprintf(SCM_PORT(ostr), msg, args__, TRUE); \
731 va_end(args__); \
732 } while (0)
733
734 /* Like SCM_ERROR_MESSAGE_FORMAT, but we also append system error message.
735 * Need to pass errno, which should be fetched by get_errno() *before*
736 * calling Scm_VM().
737 */
738 #define SCM_SYSERROR_MESSAGE_FORMAT(ostr, msg, en) \
739 do { \
740 SCM_ERROR_MESSAGE_FORMAT(ostr, msg); \
741 ScmObj syserr = get_syserrmsg(en); \
742 SCM_PUTZ(": ", -1, ostr); \
743 SCM_PUTS(syserr, ostr); \
744 } while (0)
745
746 /*
747 * C-like interface
748 */
Scm_Error(const char * msg,...)749 void Scm_Error(const char *msg, ...)
750 {
751 ScmVM *vm = Scm_VM();
752 SCM_ERROR_DOUBLE_FAULT_CHECK(vm, msg);
753 ScmObj ostr;
754 SCM_ERROR_MESSAGE_FORMAT(ostr, msg);
755 ScmObj e = Scm_MakeError(Scm_GetOutputString(SCM_PORT(ostr), TRUE));
756 Scm_VMThrowException(vm, e, SCM_RAISE_NON_CONTINUABLE);
757 Scm_Panic("Scm_Error: Scm_VMThrowException returned. something wrong.");
758 }
759
760 /*
761 * Just for convenience to report a system error. Add strerror() message
762 * after the provided message.
763 */
get_syserrmsg(int en)764 static ScmObj get_syserrmsg(int en)
765 {
766 ScmObj syserr;
767 #if !defined(GAUCHE_WINDOWS)
768 syserr = SCM_MAKE_STR_COPYING(strerror(en));
769 #else /*GAUCHE_WINDOWS*/
770 if (en < 0) {
771 ScmObj ostr = Scm_MakeOutputStringPort(TRUE);
772 LPTSTR msgbuf = NULL;
773 const char *xmsgbuf;
774 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
775 FORMAT_MESSAGE_FROM_SYSTEM |
776 FORMAT_MESSAGE_IGNORE_INSERTS,
777 NULL,
778 -en,
779 MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
780 (LPTSTR)&msgbuf,
781 0, NULL)) {
782 xmsgbuf = SCM_WCS2MBS(msgbuf);
783 SCM_PUTZ(xmsgbuf, -1, ostr);
784 }
785 LocalFree(msgbuf);
786 Scm_Printf(SCM_PORT(ostr), "(error code = %d)", -en);
787 syserr = Scm_GetOutputString(SCM_PORT(ostr), 0);
788 } else {
789 syserr = SCM_MAKE_STR_COPYING(strerror(en));
790 }
791 #endif /*GAUCHE_WINDOWS*/
792 return syserr;
793 }
794
get_errno(void)795 static int get_errno(void)
796 {
797 #if !defined(GAUCHE_WINDOWS)
798 return errno;
799 #else /*GAUCHE_WINDOWS*/
800 int en;
801
802 if (errno == 0) {
803 en = -(int)GetLastError();
804 } else {
805 en = errno; /* NB: MSDN says we should use _get_errno,
806 but MinGW doesn't seem to have it yet.*/
807 }
808
809 /* Reset the error code, so that we can find which is the actual
810 error code in the next occasion. */
811 errno = 0; /* NB: MSDN says we should use _set_errno,
812 but MinGW doesn't seem to have it yet. */
813 SetLastError(0);
814
815 return en;
816 #endif /*GAUCHE_WINDOWS*/
817 }
818
Scm_SysError(const char * msg,...)819 void Scm_SysError(const char *msg, ...)
820 {
821 int en = get_errno(); /* must take this before Scm_VM() */
822 ScmVM *vm = Scm_VM();
823 SCM_ERROR_DOUBLE_FAULT_CHECK(vm, msg);
824
825 ScmObj ostr;
826 SCM_SYSERROR_MESSAGE_FORMAT(ostr, msg, en);
827 ScmObj e = Scm_MakeSystemError(Scm_GetOutputString(SCM_PORT(ostr), TRUE), en);
828 Scm_VMThrowException(vm, e, SCM_RAISE_NON_CONTINUABLE);
829 Scm_Panic("Scm_Error: Scm_VMThrowException returned. something wrong.");
830 }
831
832 /*
833 * A convenience function to raise argument-type-violation errors.
834 * Right now it raises <error>, but it'll be changed once we adopt R6RS
835 * (The draft R6RS defines 'contract violation' in such cases).
836 */
Scm_TypeError(const char * what,const char * expected,ScmObj got)837 void Scm_TypeError(const char *what, const char *expected, ScmObj got)
838 {
839 Scm_Error("%s is supposed to be of type %s, but got %S",
840 what, expected, got);
841 }
842
843
844 /*
845 * A convenience function to raise port-related errors.
846 * It creates either one of port error instance,
847 * depending on the 'reason' argument.
848 * If errno isn't zero, it also creates a <system-error> and throws
849 * a compound condition of both.
850 */
raise_port_error(ScmVM * vm,ScmPort * port,int reason,ScmObj auxinfo,int orig_errno,const char * msg,va_list args)851 void raise_port_error(ScmVM *vm, ScmPort *port, int reason, ScmObj auxinfo,
852 int orig_errno, const char *msg, va_list args)
853 {
854 Scm_SetPortErrorOccurred(port, TRUE);
855
856 ScmObj ostr = Scm_MakeOutputStringPort(TRUE);
857 Scm_Vprintf(SCM_PORT(ostr), msg, args, TRUE);
858 ScmObj syserr = get_syserrmsg(orig_errno);
859 Scm_Putz(": ", -1, SCM_PORT(ostr));
860 Scm_Puts(SCM_STRING(syserr), SCM_PORT(ostr));
861 ScmObj smsg = Scm_GetOutputString(SCM_PORT(ostr), TRUE);
862
863 ScmClass *peclass;
864 switch (reason) {
865 case SCM_PORT_ERROR_INPUT:
866 peclass = SCM_CLASS_IO_READ_ERROR; break;
867 case SCM_PORT_ERROR_OUTPUT:
868 peclass = SCM_CLASS_IO_WRITE_ERROR; break;
869 case SCM_PORT_ERROR_CLOSED:
870 peclass = SCM_CLASS_IO_CLOSED_ERROR; break;
871 case SCM_PORT_ERROR_UNIT:
872 peclass = SCM_CLASS_IO_UNIT_ERROR; break;
873 case SCM_PORT_ERROR_DECODING:
874 peclass = SCM_CLASS_IO_DECODING_ERROR; break;
875 case SCM_PORT_ERROR_ENCODING:
876 peclass = SCM_CLASS_IO_ENCODING_ERROR; break;
877 case SCM_PORT_ERROR_SEEK:
878 peclass = SCM_CLASS_PORT_ERROR; break;
879 case SCM_PORT_ERROR_INVALID_POSITION:
880 peclass = SCM_CLASS_IO_INVALID_POSITION_ERROR; break;
881 default:
882 peclass = SCM_CLASS_PORT_ERROR; break;
883 }
884
885 ScmObj pe = porterror_allocate(peclass, SCM_NIL);
886 SCM_ERROR(pe)->message = SCM_LIST2(smsg, smsg);
887 SCM_PORT_ERROR(pe)->port = port;
888 SCM_PORT_ERROR(pe)->auxinfo = auxinfo;
889
890 ScmObj e = pe;
891 if (orig_errno != 0) {
892 e = Scm_MakeCompoundCondition(SCM_LIST2(Scm_MakeSystemError(smsg, orig_errno),
893 pe));
894 }
895 Scm_VMThrowException(vm, e, SCM_RAISE_NON_CONTINUABLE);
896 }
897
Scm_PortErrorWithAux(ScmPort * port,int reason,ScmObj auxinfo,const char * msg,...)898 void Scm_PortErrorWithAux(ScmPort *port, int reason, ScmObj auxinfo,
899 const char *msg, ...)
900 {
901 int en = get_errno(); /* must take this before Scm_VM() */
902 ScmVM *vm = Scm_VM();
903 SCM_ERROR_DOUBLE_FAULT_CHECK(vm, msg);
904
905 va_list ap;
906 va_start(ap, msg);
907 raise_port_error(vm, port, reason, auxinfo, en, msg, ap);
908 va_end(ap);
909 Scm_Panic("Scm_Error: Scm_VMThrowException returned. something wrong.");
910 }
911
Scm_PortError(ScmPort * port,int reason,const char * msg,...)912 void Scm_PortError(ScmPort *port, int reason, const char *msg, ...)
913 {
914 int en = get_errno(); /* must take this before Scm_VM() */
915 ScmVM *vm = Scm_VM();
916 SCM_ERROR_DOUBLE_FAULT_CHECK(vm, msg);
917
918 va_list ap;
919 va_start(ap, msg);
920 raise_port_error(vm, port, reason, SCM_NIL, en, msg, ap);
921 va_end(ap);
922 Scm_Panic("Scm_Error: Scm_VMThrowException returned. something wrong.");
923 }
924
925 /*
926 * Just print warning
927 * TODO: customize behavior
928 */
929
Scm_Warn(const char * msg,...)930 void Scm_Warn(const char *msg, ...)
931 {
932 if (Scm_GetEnv("GAUCHE_SUPPRESS_WARNING") != NULL) return;
933 va_list args;
934 va_start(args, msg);
935 Scm_Printf(SCM_CURERR, "WARNING: %A\n", Scm_Vsprintf(msg, args, TRUE));
936 Scm_Flush(SCM_CURERR);
937 va_end(args);
938 }
939
940 /* OBSOLETED: 'warn' is now in Scheme. */
Scm_FWarn(ScmString * fmt SCM_UNUSED,ScmObj args SCM_UNUSED)941 void Scm_FWarn(ScmString *fmt SCM_UNUSED, ScmObj args SCM_UNUSED)
942 {
943 Scm_Error("Scm_FWarn is obsoleted");
944 }
945
946 /*
947 * General exception raising
948 */
949
950 /* An external API to hide Scm_VMThrowException. */
Scm_Raise(ScmObj condition,u_long flags)951 ScmObj Scm_Raise(ScmObj condition, u_long flags)
952 {
953 return Scm_VMThrowException(Scm_VM(), condition, flags);
954 }
955
956
957 /* A convenient API---allows to call user-defined condition easily,
958 even the condition type is defined in Scheme. For example:
959
960 Scm_RaiseCondition(SCM_SYMBOL_VALUE("mymodule", "<my-error>"),
961 "error-type", SCM_INTERN("fatal"),
962 "error-code", SCM_MAKE_INT(3),
963 SCM_RAISE_CONDITION_MESSAGE,
964 "Fatal error occurred at %S", current_proc);
965
966 roughly corresponds to the Scheme code:
967
968 (raise (condition
969 (<my-error> (error-type 'fatal)
970 (error-code 3)
971 (message (format "Fatal error occurred at ~s"
972 current_proc)))))
973
974 This function isn't very efficient; but sometimes you want the convenience
975 more, right?
976
977 The argument list format:
978
979 <condition-type> {<string-slot-name> <value>}* <terminator>
980
981 <terminator> : SCM_RAISE_CONDITION_MESSAGE <fmtstr> <fmtarg> ...
982 | NULL
983 */
984
Scm_RaiseCondition(ScmObj condition_type,...)985 ScmObj Scm_RaiseCondition(ScmObj condition_type, ...)
986 {
987 ScmObj argh = SCM_NIL, argt = SCM_NIL;
988 va_list ap;
989
990 if (!SCM_CLASSP(condition_type)
991 || !Scm_SubtypeP(SCM_CLASS(condition_type), SCM_CLASS_CONDITION)) {
992 /* If we don't get a condition type, fallback to a normal error. */
993 condition_type = SCM_OBJ(SCM_CLASS_ERROR);
994 }
995 SCM_APPEND1(argh, argt, condition_type);
996 va_start(ap, condition_type);
997 for (;;) {
998 const char *key = va_arg(ap, const char *);
999 if (key == NULL) {
1000 break;
1001 } else if (key == SCM_RAISE_CONDITION_MESSAGE) {
1002 const char *msg = va_arg(ap, const char*);
1003 ScmObj ostr = Scm_MakeOutputStringPort(TRUE);
1004 Scm_Vprintf(SCM_PORT(ostr), msg, ap, TRUE);
1005 SCM_APPEND1(argh, argt, SCM_MAKE_KEYWORD("message"));
1006 SCM_APPEND1(argh, argt, Scm_GetOutputString(SCM_PORT(ostr), 0));
1007 break;
1008 } else {
1009 ScmObj arg = va_arg(ap, ScmObj);
1010 SCM_APPEND1(argh, argt, SCM_MAKE_KEYWORD(key));
1011 SCM_APPEND1(argh, argt, arg);
1012 }
1013 }
1014 va_end(ap);
1015 return Scm_ApplyRec(SCM_SYMBOL_VALUE("gauche", "error"), argh);
1016 }
1017
1018 /*
1019 * Show stack or call trace.
1020 * stacklite - return value of Scm_VMGetStackLite or Scm_VMGetCallTraceLite
1021 * maxdepth - maximum # of entries to be shown.
1022 * 0 to use the default. -1 for unlimited.
1023 * skip - ignore this number of frames. Useful to call this from
1024 * a Scheme error handling routine, in order to skip the
1025 * frames of the handler itself.
1026 * offset - add this to the frame number. Useful to show a middle part
1027 * of frames only, by combining the skip parameter.
1028 * format - SCM_STACK_TRACE_FORMAT_* enum value. No longer used.
1029 */
Scm_ShowStackTrace(ScmPort * out,ScmObj stacklite,int maxdepth,int skip,int offset,int format SCM_UNUSED)1030 void Scm_ShowStackTrace(ScmPort *out, ScmObj stacklite,
1031 int maxdepth, int skip, int offset,
1032 int format SCM_UNUSED)
1033 {
1034 static ScmObj show_stack_trace = SCM_UNDEFINED;
1035 SCM_BIND_PROC(show_stack_trace,
1036 "%show-stack-trace",
1037 Scm_GaucheInternalModule());
1038 Scm_ApplyRec5(show_stack_trace, stacklite, SCM_OBJ(out),
1039 SCM_MAKE_INT(maxdepth), SCM_MAKE_INT(skip),
1040 SCM_MAKE_INT(offset));
1041 }
1042
1043 /* Dump stack trace. Called from the default error reporter.
1044 Also intended to be called from the debugger, so we allow vm to be NULL
1045 to mean the current VM, and port to be NULL for the current error port. */
Scm_DumpStackTrace(ScmVM * vm,ScmPort * port)1046 void Scm_DumpStackTrace(ScmVM *vm, ScmPort *port)
1047 {
1048 if (vm == NULL) vm = Scm_VM();
1049 if (port == NULL) port = SCM_VM_CURRENT_ERROR_PORT(vm);
1050 ScmObj stack = Scm_VMGetStackLite(vm);
1051 ScmObj calls = Scm_VMGetCallTraceLite(vm);
1052 SCM_PUTZ("Stack Trace:\n", -1, port);
1053 SCM_PUTZ("_______________________________________\n", -1, port);
1054 Scm_ShowStackTrace(port, stack, 0, 0, 0, 0);
1055 if (SCM_PAIRP(calls)) {
1056 SCM_PUTZ("Call Trace:\n", -1, port);
1057 SCM_PUTZ("_______________________________________\n", -1, port);
1058 Scm_ShowStackTrace(port, calls, 0, 0, 0, 0);
1059 }
1060 SCM_FLUSH(port);
1061 }
1062
1063 /*
1064 * Default error reporter
1065 */
1066
1067 /* The default procedure to display the header of error message.
1068 E is a thrown condition, not necessarily an error object.
1069
1070 The actual operation is written in Scheme (libexc.scm). However,
1071 we can't use that before the infrastructure is fully booted; so
1072 this routine has a fallback which will be used only during initialization.
1073 */
Scm_PrintDefaultErrorHeading(ScmObj e,ScmPort * out)1074 static void Scm_PrintDefaultErrorHeading(ScmObj e, ScmPort *out)
1075 {
1076 if (Scm_InitializedP()) {
1077 static ScmObj print_default_error_heading = SCM_UNDEFINED;
1078 SCM_BIND_PROC(print_default_error_heading,
1079 "print-default-error-heading",
1080 Scm_GaucheModule());
1081 Scm_ApplyRec2(print_default_error_heading, e, SCM_OBJ(out));
1082 } else {
1083 /* Error during initialization. */
1084 if (SCM_CONDITIONP(e)) {
1085 Scm_Printf(out, "*** %A: %A\n",
1086 Scm_ConditionTypeName(e),
1087 Scm_ConditionMessage(e));
1088 } else {
1089 Scm_Printf(out, "*** ERROR: Unhandled condition: %S\n", e);
1090 }
1091 }
1092 }
1093
1094 /* We treat out == #f or #t just like 'format' - #t for the current output
1095 port, and #f for string port. If it's output port, use it. For any
1096 other objects, we use current error port. This permissive behavior is
1097 intentional - report-error is usually called during error handling,
1098 and raising an error there masks the original error. However, the
1099 caller should explicitly pass SCM_OBJ(SCM_CURERR) if that's what it intends,
1100 instead of relying on the permissive behavior.
1101 */
Scm_ReportError(ScmObj e,ScmObj out)1102 ScmObj Scm_ReportError(ScmObj e, ScmObj out)
1103 {
1104 ScmVM *vm = Scm_VM();
1105 ScmPort *port = SCM_VM_CURRENT_ERROR_PORT(vm);
1106 if (SCM_FALSEP(out)) {
1107 port = SCM_PORT(Scm_MakeOutputStringPort(TRUE));
1108 } else if (SCM_TRUEP(out)) {
1109 port = SCM_VM_CURRENT_OUTPUT_PORT(vm);
1110 } else if (SCM_OPORTP(out)) {
1111 port = SCM_PORT(out);
1112 }
1113 Scm_PrintDefaultErrorHeading(e, port);
1114 Scm_DumpStackTrace(vm, port);
1115 if (SCM_FALSEP(out)) return Scm_GetOutputString(SCM_PORT(port), 0);
1116 else return SCM_UNDEFINED;
1117 }
1118
1119 /*
1120 * Initialization
1121 */
Scm__InitExceptions(void)1122 void Scm__InitExceptions(void)
1123 {
1124 ScmModule *mod = Scm_GaucheModule();
1125
1126 ScmObj mes_ser_supers
1127 = SCM_LIST2(SCM_OBJ(SCM_CLASS_MESSAGE_CONDITION),
1128 SCM_OBJ(SCM_CLASS_SERIOUS_CONDITION));
1129 ScmObj com_ser_supers
1130 = SCM_LIST2(SCM_OBJ(SCM_CLASS_COMPOUND_CONDITION),
1131 SCM_OBJ(SCM_CLASS_SERIOUS_CONDITION));
1132
1133 Scm_InitStaticClassWithMeta(SCM_CLASS_CONDITION,
1134 "<condition>",
1135 mod, NULL, SCM_FALSE, NULL, 0);
1136 ScmClass *cond_meta = Scm_ClassOf(SCM_OBJ(SCM_CLASS_CONDITION));
1137 Scm_InitStaticClassWithMeta(SCM_CLASS_SERIOUS_CONDITION,
1138 "<serious-condition>",
1139 mod, cond_meta, SCM_FALSE, NULL, 0);
1140 Scm_InitStaticClassWithMeta(SCM_CLASS_MESSAGE_CONDITION,
1141 "<message-condition>",
1142 mod, cond_meta, SCM_FALSE, message_slots, 0);
1143 Scm_InitStaticClassWithMeta(SCM_CLASS_MIXIN_CONDITION,
1144 "<mixin-condition>",
1145 mod, cond_meta, SCM_FALSE, NULL, 0);
1146
1147 Scm_InitStaticClassWithMeta(SCM_CLASS_ERROR,
1148 "<error>",
1149 mod, cond_meta, mes_ser_supers,
1150 message_slots, 0);
1151 Scm_InitStaticClassWithMeta(SCM_CLASS_SYSTEM_ERROR,
1152 "<system-error>",
1153 mod, cond_meta, SCM_FALSE,
1154 syserror_slots, 0);
1155 Scm_InitStaticClassWithMeta(SCM_CLASS_UNHANDLED_SIGNAL_ERROR,
1156 "<unhandled-signal-error>",
1157 mod, cond_meta, SCM_FALSE,
1158 sigerror_slots, 0);
1159 Scm_InitStaticClassWithMeta(SCM_CLASS_READ_ERROR,
1160 "<read-error>",
1161 mod, cond_meta, SCM_FALSE,
1162 readerror_slots, 0);
1163 Scm_InitStaticClassWithMeta(SCM_CLASS_IO_ERROR,
1164 "<io-error>",
1165 mod, cond_meta, SCM_FALSE,
1166 NULL, 0);
1167 Scm_InitStaticClassWithMeta(SCM_CLASS_PORT_ERROR,
1168 "<port-error>",
1169 mod, cond_meta, SCM_FALSE,
1170 porterror_slots, 0);
1171 Scm_InitStaticClassWithMeta(SCM_CLASS_IO_READ_ERROR,
1172 "<io-read-error>",
1173 mod, cond_meta, SCM_FALSE,
1174 porterror_slots, 0);
1175 Scm_InitStaticClassWithMeta(SCM_CLASS_IO_WRITE_ERROR,
1176 "<io-write-error>",
1177 mod, cond_meta, SCM_FALSE,
1178 porterror_slots, 0);
1179 Scm_InitStaticClassWithMeta(SCM_CLASS_IO_CLOSED_ERROR,
1180 "<io-closed-error>",
1181 mod, cond_meta, SCM_FALSE,
1182 porterror_slots, 0);
1183 Scm_InitStaticClassWithMeta(SCM_CLASS_IO_UNIT_ERROR,
1184 "<io-unit-error>",
1185 mod, cond_meta, SCM_FALSE,
1186 porterror_slots, 0);
1187 Scm_InitStaticClassWithMeta(SCM_CLASS_IO_DECODING_ERROR,
1188 "<io-decoding-error>",
1189 mod, cond_meta, SCM_FALSE,
1190 porterror_slots, 0);
1191 Scm_InitStaticClassWithMeta(SCM_CLASS_IO_ENCODING_ERROR,
1192 "<io-encoding-error>",
1193 mod, cond_meta, SCM_FALSE,
1194 encodingerror_slots, 0);
1195 Scm_InitStaticClassWithMeta(SCM_CLASS_IO_INVALID_POSITION_ERROR,
1196 "<io-invalid-position-error>",
1197 mod, cond_meta, SCM_FALSE,
1198 invalidpositionerror_slots, 0);
1199
1200 Scm_InitStaticClassWithMeta(SCM_CLASS_COMPOUND_CONDITION,
1201 "<compound-condition>",
1202 mod, cond_meta, SCM_FALSE,
1203 compound_slots, 0);
1204 Scm_InitStaticClassWithMeta(SCM_CLASS_SERIOUS_COMPOUND_CONDITION,
1205 "<serious-compound-condition>",
1206 mod, cond_meta, com_ser_supers,
1207 compound_slots, 0);
1208
1209 sym_offending_char = SCM_INTERN("offending-char");
1210 sym_position = SCM_INTERN("position");
1211 }
1212