2 ** error.c - Exception class
4 ** See Copyright Notice in mruby.h
10 #include <mruby/array.h>
11 #include <mruby/irep.h>
12 #include <mruby/proc.h>
13 #include <mruby/string.h>
14 #include <mruby/variable.h>
15 #include <mruby/error.h>
16 #include <mruby/class.h>
17 #include <mruby/throw.h>
18 #include <mruby/internal.h>
19 #include <mruby/presym.h>
22 mrb_exc_mesg_set(mrb_state
*mrb
, struct RException
*exc
, mrb_value mesg
)
24 if (!mrb_string_p(mesg
)) {
25 mesg
= mrb_obj_as_string(mrb
, mesg
);
27 exc
->mesg
= mrb_basic_ptr(mesg
);
28 mrb_field_write_barrier_value(mrb
, (struct RBasic
*)exc
, mesg
);
32 mrb_exc_mesg_get(mrb_state
*mrb
, struct RException
*exc
)
34 if (exc
->mesg
== NULL
) return mrb_nil_value();
35 return mrb_obj_value(exc
->mesg
);
39 mrb_exc_new_str(mrb_state
*mrb
, struct RClass
* c
, mrb_value str
)
41 mrb_ensure_string_type(mrb
, str
);
43 struct RException
*e
= MRB_OBJ_ALLOC(mrb
, MRB_TT_EXCEPTION
, c
);
44 mrb_value exc
= mrb_obj_value(e
);
45 mrb_exc_mesg_set(mrb
, e
, str
);
50 mrb_exc_new(mrb_state
*mrb
, struct RClass
*c
, const char *ptr
, mrb_int len
)
52 return mrb_exc_new_str(mrb
, c
, mrb_str_new(mrb
, ptr
, len
));
57 * Exception.new(msg = nil) -> exception
59 * Construct a new Exception object, optionally passing in
64 exc_initialize(mrb_state
*mrb
, mrb_value exc
)
68 if (mrb_get_args(mrb
, "|o", &mesg
) == 1) {
69 mrb_exc_mesg_set(mrb
, mrb_exc_ptr(exc
), mesg
);
75 * Document-method: exception
78 * exc.exception(string) -> an_exception or exc
80 * With no argument, or if the argument is the same as the receiver,
81 * return the receiver. Otherwise, create a new
82 * exception object of the same class as the receiver, but with a
83 * message equal to <code>string</code>.
88 exc_exception(mrb_state
*mrb
, mrb_value self
)
91 mrb_int argc
= mrb_get_args(mrb
, "|o", &a
);
93 if (argc
== 0) return self
;
94 if (mrb_obj_equal(mrb
, self
, a
)) return self
;
96 mrb_value exc
= mrb_obj_clone(mrb
, self
);
97 mrb_exc_mesg_set(mrb
, mrb_exc_ptr(exc
), a
);
104 * exception.to_s -> string
106 * Returns exception's message (or the name of the exception if
107 * no message is set).
111 exc_to_s(mrb_state
*mrb
, mrb_value exc
)
113 mrb_value mesg
= mrb_exc_mesg_get(mrb
, mrb_exc_ptr(exc
));
115 if (!mrb_string_p(mesg
)) {
116 return mrb_str_new_cstr(mrb
, mrb_obj_classname(mrb
, exc
));
118 struct RObject
*p
= mrb_obj_ptr(mesg
);
120 p
->c
= mrb
->string_class
;
127 * exception.inspect -> string
129 * Returns this exception's file name, line number,
130 * message and class name.
131 * If file name or line number is not set,
132 * returns message and class name.
136 mrb_exc_inspect(mrb_state
*mrb
, mrb_value exc
)
138 mrb_value cname
= mrb_mod_to_s(mrb
, mrb_obj_value(mrb_obj_class(mrb
, exc
)));
139 mrb_value mesg
= mrb_exc_mesg_get(mrb
, mrb_exc_ptr(exc
)); /* string or nil */
140 return (mrb_nil_p(mesg
)||RSTRING_LEN(mesg
)==0) ? cname
: mrb_format(mrb
, "%v (%v)", mesg
, cname
);
143 void mrb_keep_backtrace(mrb_state
*mrb
, mrb_value exc
);
146 set_backtrace(mrb_state
*mrb
, mrb_value exc
, mrb_value backtrace
)
148 if (!mrb_array_p(backtrace
)) {
150 mrb_raise(mrb
, E_TYPE_ERROR
, "backtrace must be Array of String");
153 const mrb_value
*p
= RARRAY_PTR(backtrace
);
154 const mrb_value
*pend
= p
+ RARRAY_LEN(backtrace
);
157 if (!mrb_string_p(*p
)) goto type_err
;
161 mrb_exc_ptr(exc
)->backtrace
= mrb_basic_ptr(backtrace
);
162 mrb_field_write_barrier_value(mrb
, mrb_basic_ptr(exc
), backtrace
);
166 exc_set_backtrace(mrb_state
*mrb
, mrb_value exc
)
168 mrb_value backtrace
= mrb_get_arg1(mrb
);
170 set_backtrace(mrb
, exc
, backtrace
);
175 mrb_exc_set(mrb_state
*mrb
, mrb_value exc
)
177 if (mrb_nil_p(exc
)) {
181 mrb
->exc
= mrb_obj_ptr(exc
);
182 if (mrb
->gc
.arena_idx
> 0 &&
183 (struct RBasic
*)mrb
->exc
== mrb
->gc
.arena
[mrb
->gc
.arena_idx
-1]) {
186 if (!mrb
->gc
.out_of_memory
&& !mrb_frozen_p(mrb
->exc
)) {
187 mrb_keep_backtrace(mrb
, exc
);
192 static mrb_noreturn
void
193 exc_throw(mrb_state
*mrb
, mrb_value exc
)
196 mrb_print_error(mrb
);
202 MRB_API mrb_noreturn
void
203 mrb_exc_raise(mrb_state
*mrb
, mrb_value exc
)
205 if (mrb_break_p(exc
)) {
206 mrb
->exc
= mrb_obj_ptr(exc
);
209 if (mrb_type(exc
) != MRB_TT_EXCEPTION
) {
210 mrb_raise(mrb
, E_TYPE_ERROR
, "exception object expected");
212 mrb_exc_set(mrb
, exc
);
217 MRB_API mrb_noreturn
void
218 mrb_raise(mrb_state
*mrb
, struct RClass
*c
, const char *msg
)
220 mrb_exc_raise(mrb
, mrb_exc_new_str(mrb
, c
, mrb_str_new_cstr(mrb
, msg
)));
224 * <code>vsprintf</code> like formatting.
226 * The syntax of a format sequence is as follows.
228 * %[modifier]specifier
232 * ----------+------------------------------------------------------------
234 * ----------+------------------------------------------------------------
235 * ! | Convert to string by corresponding `inspect` instead of
236 * | corresponding `to_s`.
237 * ----------+------------------------------------------------------------
239 * The specifiers are:
241 * ----------+----------------+--------------------------------------------
242 * Specifier | Argument Type | Note
243 * ----------+----------------+--------------------------------------------
248 * l | char*, size_t | Arguments are string and length.
250 * s | char* | Argument is NUL terminated string.
251 * t | mrb_value | Convert to type (class) of object.
253 * C | struct RClass* |
254 * T | mrb_value | Convert to real type (class) of object.
255 * Y | mrb_value | Same as `!v` if argument is `true`, `false`
256 * | | or `nil`, otherwise same as `T`.
257 * % | - | Convert to percent sign itself (no argument
259 * ----------+----------------+--------------------------------------------
262 mrb_vformat(mrb_state
*mrb
, const char *format
, va_list ap
)
264 const char *chars
, *p
= format
, *b
= format
, *e
;
269 mrb_bool inspect
= FALSE
;
270 mrb_value result
= mrb_str_new_capa(mrb
, 128), obj
, str
;
271 int ai
= mrb_gc_arena_save(mrb
);
284 ch
= (char)va_arg(ap
, int);
289 #if MRB_INT_MAX < INT_MAX
290 i
= (mrb_int
)va_arg(ap
, int);
292 i
= *p
== 'd' ? (mrb_int
)va_arg(ap
, int) : va_arg(ap
, mrb_int
);
294 obj
= mrb_int_value(mrb
, i
);
298 obj
= mrb_float_value(mrb
, (mrb_float
)va_arg(ap
, double));
302 chars
= va_arg(ap
, char*);
303 len
= va_arg(ap
, size_t);
306 obj
= mrb_str_new(mrb
, chars
, len
);
310 mrb_str_cat(mrb
, result
, b
, e
- b
- 1);
311 mrb_str_cat(mrb
, result
, chars
, len
);
313 mrb_gc_arena_restore(mrb
, ai
);
316 #if UINT32_MAX < INT_MAX
317 obj
= mrb_symbol_value((mrb_sym
)va_arg(ap
, int));
319 obj
= mrb_symbol_value(va_arg(ap
, mrb_sym
));
323 chars
= va_arg(ap
, char*);
327 cls
= mrb_class(mrb
, va_arg(ap
, mrb_value
));
330 obj
= va_arg(ap
, mrb_value
);
332 str
= (inspect
? mrb_inspect
: mrb_obj_as_string
)(mrb
, obj
);
333 if (mrb_type(str
) != MRB_TT_STRING
) {
334 chars
= "void (no string conversion)";
338 chars
= RSTRING_PTR(str
);
339 len
= RSTRING_LEN(str
);
343 cls
= va_arg(ap
, struct RClass
*);
345 obj
= mrb_obj_value(cls
);
348 obj
= va_arg(ap
, mrb_value
);
350 cls
= mrb_obj_class(mrb
, obj
);
353 obj
= va_arg(ap
, mrb_value
);
354 if (!mrb_test(obj
) || mrb_true_p(obj
)) {
359 goto L_cat_real_class_of
;
367 mrb_raisef(mrb
, E_ARGUMENT_ERROR
, "malformed format string - %%%c", *p
);
370 else if (c
== '\\') {
377 mrb_str_cat(mrb
, result
, b
, p
- b
);
382 mrb_format(mrb_state
*mrb
, const char *format
, ...)
386 va_start(ap
, format
);
388 mrb_value str
= mrb_vformat(mrb
, format
, ap
);
395 error_va(mrb_state
*mrb
, struct RClass
*c
, const char *fmt
, va_list ap
)
397 return mrb_exc_new_str(mrb
, c
, mrb_vformat(mrb
, fmt
, ap
));
400 MRB_API mrb_noreturn
void
401 mrb_raisef(mrb_state
*mrb
, struct RClass
*c
, const char *fmt
, ...)
407 mrb_value exc
= error_va(mrb
, c
, fmt
, ap
);
410 mrb_exc_raise(mrb
, exc
);
413 MRB_API mrb_noreturn
void
414 mrb_name_error(mrb_state
*mrb
, mrb_sym id
, const char *fmt
, ...)
420 mrb_value exc
= error_va(mrb
, E_NAME_ERROR
, fmt
, ap
);
422 mrb_iv_set(mrb
, exc
, MRB_IVSYM(name
), mrb_symbol_value(id
));
423 mrb_exc_raise(mrb
, exc
);
427 mrb_warn(mrb_state
*mrb
, const char *fmt
, ...)
434 mrb_value str
= mrb_vformat(mrb
, fmt
, ap
);
435 fputs("warning: ", stderr
);
436 fwrite(RSTRING_PTR(str
), RSTRING_LEN(str
), 1, stderr
);
442 MRB_API mrb_noreturn
void
443 mrb_bug(mrb_state
*mrb
, const char *mesg
)
446 fputs("bug: ", stderr
);
454 mrb_make_exception(mrb_state
*mrb
, mrb_value exc
, mrb_value mesg
)
458 if (mrb_nil_p(mesg
)) {
461 if (mrb_class_p(exc
)) {
462 exc
= mrb_funcall_argv(mrb
, exc
, MRB_SYM(new), n
, &mesg
);
464 else if (mrb_exception_p(exc
)) {
466 exc
= mrb_obj_clone(mrb
, exc
);
467 mrb_exc_mesg_set(mrb
, mrb_exc_ptr(exc
), mesg
);
471 mrb_raise(mrb
, E_TYPE_ERROR
, "exception class/object expected");
473 if (mrb_type(exc
) != MRB_TT_EXCEPTION
) {
474 mrb_raise(mrb
, E_EXCEPTION
, "exception object expected");
479 MRB_API mrb_noreturn
void
480 mrb_sys_fail(mrb_state
*mrb
, const char *mesg
)
482 if (mrb_class_defined_id(mrb
, MRB_SYM(SystemCallError
))) {
483 struct RClass
*sce
= mrb_class_get_id(mrb
, MRB_SYM(SystemCallError
));
484 mrb_int no
= (mrb_int
)errno
;
486 mrb_funcall_id(mrb
, mrb_obj_value(sce
), MRB_SYM(_sys_fail
), 2, mrb_fixnum_value(no
), mrb_str_new_cstr(mrb
, mesg
));
489 mrb_funcall_id(mrb
, mrb_obj_value(sce
), MRB_SYM(_sys_fail
), 1, mrb_fixnum_value(no
));
493 mrb_raise(mrb
, E_RUNTIME_ERROR
, mesg
);
496 MRB_API mrb_noreturn
void
497 mrb_no_method_error(mrb_state
*mrb
, mrb_sym id
, mrb_value args
, char const* fmt
, ...)
503 mrb_value exc
= error_va(mrb
, E_NOMETHOD_ERROR
, fmt
, ap
);
505 mrb_iv_set(mrb
, exc
, MRB_IVSYM(name
), mrb_symbol_value(id
));
506 mrb_iv_set(mrb
, exc
, MRB_IVSYM(args
), args
);
507 mrb_exc_raise(mrb
, exc
);
510 static mrb_noreturn
void
511 frozen_error(mrb_state
*mrb
, mrb_value v
)
513 mrb_raisef(mrb
, E_FROZEN_ERROR
, "can't modify frozen %T", v
);
516 MRB_API mrb_noreturn
void
517 mrb_frozen_error(mrb_state
*mrb
, void *frozen_obj
)
519 frozen_error(mrb
, mrb_obj_value(frozen_obj
));
523 mrb_check_frozen(mrb_state
*mrb
, void *o
)
525 if (mrb_frozen_p((struct RBasic
*)o
)) {
526 mrb_frozen_error(mrb
, o
);
531 mrb_check_frozen_value(mrb_state
*mrb
, mrb_value v
)
533 if (mrb_immediate_p(v
) || mrb_frozen_p(mrb_basic_ptr(v
))) {
534 frozen_error(mrb
, v
);
538 MRB_API mrb_noreturn
void
539 mrb_argnum_error(mrb_state
*mrb
, mrb_int argc
, int min
, int max
)
541 #define FMT(exp) "wrong number of arguments (given %i, expected " exp ")"
543 mrb_raisef(mrb
, E_ARGUMENT_ERROR
, FMT("%d"), argc
, min
);
545 mrb_raisef(mrb
, E_ARGUMENT_ERROR
, FMT("%d+"), argc
, min
);
547 mrb_raisef(mrb
, E_ARGUMENT_ERROR
, FMT("%d..%d"), argc
, min
, max
);
551 void mrb_core_init_printabort(void);
554 mrb_core_init_protect(mrb_state
*mrb
, void (*body
)(mrb_state
*, void*), void *opaque
)
556 struct mrb_jmpbuf
*prev_jmp
= mrb
->jmp
;
557 struct mrb_jmpbuf c_jmp
;
558 volatile int err
= 1;
564 } MRB_CATCH(&c_jmp
) {
566 mrb_print_error(mrb
);
570 mrb_core_init_printabort();
572 } MRB_END_EXC(&c_jmp
);
580 mrb_core_init_abort(mrb_state
*mrb
)
583 exc_throw(mrb
, mrb_nil_value());
587 mrb_protect_atexit(mrb_state
*mrb
)
589 if (mrb
->atexit_stack_len
> 0) {
590 if (mrb
->c
&& mrb
->c
->ci
) {
591 // Even if the call stack is incomplete due to some fault, atexit to be executed at the top level is desirable.
592 // Clean-up also makes it easier to collect unnecessary objects.
593 mrb_callinfo zero
= { 0 };
594 struct mrb_context
*c
= mrb
->c
= mrb
->root_c
;
597 c
->ci
->stack
= c
->stbase
;
598 mrb_gc_arena_restore(mrb
, 0);
601 struct mrb_jmpbuf
*prev_jmp
= mrb
->jmp
;
602 struct mrb_jmpbuf c_jmp
;
603 int i
= mrb
->atexit_stack_len
;
608 mrb
->atexit_stack
[--i
](mrb
);
609 mrb_gc_arena_restore(mrb
, 0);
612 } MRB_CATCH(&c_jmp
) {
614 /* ignore atexit errors */
615 mrb_gc_arena_restore(mrb
, 0);
616 } MRB_END_EXC(&c_jmp
);
618 #ifndef MRB_FIXED_STATE_ATEXIT_STACK
619 mrb_free(mrb
, mrb
->atexit_stack
);
625 mrb_raise_nomemory(mrb_state
*mrb
)
627 if (mrb
->nomem_err
) {
628 mrb_exc_raise(mrb
, mrb_obj_value(mrb
->nomem_err
));
631 mrb_core_init_abort(mrb
);
636 mrb_print_error(mrb_state
*mrb
)
639 if (mrb
->jmp
== NULL
) {
640 struct mrb_jmpbuf c_jmp
;
643 mrb_print_backtrace(mrb
);
644 } MRB_CATCH(&c_jmp
) {
645 /* ignore exception during print_backtrace() */
646 } MRB_END_EXC(&c_jmp
);
650 mrb_print_backtrace(mrb
);
655 /* clear error status in the mrb_state structure */
657 mrb_clear_error(mrb_state
*mrb
)
662 /* returns TRUE if error in the previous call; internally calls mrb_clear_error() */
664 mrb_check_error(mrb_state
*mrb
)
667 mrb_clear_error(mrb
);
674 mrb_init_exception(mrb_state
*mrb
)
676 struct RClass
*exception
= mrb
->eException_class
= mrb_define_class_id(mrb
, MRB_SYM(Exception
), mrb
->object_class
); /* 15.2.22 */
677 MRB_SET_INSTANCE_TT(exception
, MRB_TT_EXCEPTION
);
678 mrb_define_class_method_id(mrb
, exception
, MRB_SYM(exception
), mrb_instance_new
, MRB_ARGS_OPT(1));
679 mrb_define_method_id(mrb
, exception
, MRB_SYM(exception
), exc_exception
, MRB_ARGS_OPT(1));
680 mrb_define_method_id(mrb
, exception
, MRB_SYM(initialize
), exc_initialize
, MRB_ARGS_OPT(1));
681 mrb_define_method_id(mrb
, exception
, MRB_SYM(to_s
), exc_to_s
, MRB_ARGS_NONE());
682 mrb_define_method_id(mrb
, exception
, MRB_SYM(inspect
), mrb_exc_inspect
, MRB_ARGS_NONE());
683 mrb_define_method_id(mrb
, exception
, MRB_SYM(backtrace
), mrb_exc_backtrace
, MRB_ARGS_NONE());
684 mrb_define_method_id(mrb
, exception
, MRB_SYM(set_backtrace
), exc_set_backtrace
, MRB_ARGS_REQ(1));
686 mrb
->eStandardError_class
= mrb_define_class_id(mrb
, MRB_SYM(StandardError
), mrb
->eException_class
); /* 15.2.23 */
687 mrb_define_class_id(mrb
, MRB_SYM(RuntimeError
), E_STANDARD_ERROR
); /* 15.2.28 */
688 struct RClass
*script_error
= mrb_define_class_id(mrb
, MRB_SYM(ScriptError
), exception
); /* 15.2.37 */
689 mrb_define_class_id(mrb
, MRB_SYM(SyntaxError
), script_error
); /* 15.2.38 */
690 struct RClass
*stack_error
= mrb_define_class_id(mrb
, MRB_SYM(SystemStackError
), exception
);
691 mrb
->stack_err
= mrb_obj_ptr(mrb_exc_new_lit(mrb
, stack_error
, "stack level too deep"));
693 struct RClass
*nomem_error
= mrb_define_class_id(mrb
, MRB_SYM(NoMemoryError
), exception
);
694 mrb
->nomem_err
= mrb_obj_ptr(mrb_exc_new_lit(mrb
, nomem_error
, "Out of memory"));
695 #ifdef MRB_GC_FIXED_ARENA
696 mrb
->arena_err
= mrb_obj_ptr(mrb_exc_new_lit(mrb
, nomem_error
, "arena overflow error"));