9fc6fe468659703bdb3829d7f1014fefe221a072
[mruby.git] / src / error.c
blob9fc6fe468659703bdb3829d7f1014fefe221a072
1 /*
2 ** error.c - Exception class
3 **
4 ** See Copyright Notice in mruby.h
5 */
7 #include <errno.h>
8 #include <stdarg.h>
9 #include <stdlib.h>
10 #include "mruby.h"
11 #include "mruby/array.h"
12 #include "mruby/irep.h"
13 #include "mruby/proc.h"
14 #include "mruby/string.h"
15 #include "mruby/variable.h"
16 #include "mruby/debug.h"
17 #include "mruby/error.h"
18 #include "mruby/class.h"
19 #include "mrb_throw.h"
21 static void
22 exc_mesg_set(mrb_state *mrb, struct RException *exc, mrb_value mesg)
24 exc->flags |= MRB_EXC_MESG_INIT_FLAG;
25 exc->mesg = mesg;
26 mrb_field_write_barrier_value(mrb, (struct RBasic*)exc, mesg);
29 static mrb_value
30 exc_mesg_get(mrb_state *mrb, struct RException *exc)
32 return (exc->flags & MRB_EXC_MESG_INIT_FLAG) != 0 ? exc->mesg : mrb_nil_value();
35 mrb_value
36 mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len)
38 mrb_value arg = mrb_str_new(mrb, ptr, len);
39 return mrb_obj_new(mrb, c, 1, &arg);
42 mrb_value
43 mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str)
45 str = mrb_str_to_str(mrb, str);
46 return mrb_obj_new(mrb, c, 1, &str);
50 * call-seq:
51 * Exception.new(msg = nil) -> exception
53 * Construct a new Exception object, optionally passing in
54 * a message.
57 static mrb_value
58 exc_initialize(mrb_state *mrb, mrb_value exc)
60 mrb_value mesg;
62 if (mrb_get_args(mrb, "|o", &mesg) == 1) {
63 exc_mesg_set(mrb, mrb_exc_ptr(exc), mesg);
65 return exc;
69 * Document-method: exception
71 * call-seq:
72 * exc.exception(string) -> an_exception or exc
74 * With no argument, or if the argument is the same as the receiver,
75 * return the receiver. Otherwise, create a new
76 * exception object of the same class as the receiver, but with a
77 * message equal to <code>string.to_str</code>.
81 static mrb_value
82 exc_exception(mrb_state *mrb, mrb_value self)
84 mrb_value exc;
85 mrb_value a;
86 int argc;
88 argc = mrb_get_args(mrb, "|o", &a);
89 if (argc == 0) return self;
90 if (mrb_obj_equal(mrb, self, a)) return self;
91 exc = mrb_obj_clone(mrb, self);
92 exc_mesg_set(mrb, mrb_exc_ptr(exc), a);
94 return exc;
98 * call-seq:
99 * exception.to_s -> string
101 * Returns exception's message (or the name of the exception if
102 * no message is set).
105 static mrb_value
106 exc_to_s(mrb_state *mrb, mrb_value exc)
108 mrb_value mesg = exc_mesg_get(mrb, mrb_exc_ptr(exc));
109 struct RObject *p;
111 if (!mrb_string_p(mesg)) {
112 return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
114 p = mrb_obj_ptr(mesg);
115 if (!p->c) {
116 p->c = mrb->string_class;
118 return mesg;
122 * call-seq:
123 * exception.message -> string
125 * Returns the result of invoking <code>exception.to_s</code>.
126 * Normally this returns the exception's message or name. By
127 * supplying a to_str method, exceptions are agreeing to
128 * be used where Strings are expected.
131 static mrb_value
132 exc_message(mrb_state *mrb, mrb_value exc)
134 return mrb_funcall(mrb, exc, "to_s", 0);
138 * call-seq:
139 * exception.inspect -> string
141 * Returns this exception's file name, line number,
142 * message and class name.
143 * If file name or line number is not set,
144 * returns message and class name.
147 static mrb_value
148 exc_inspect(mrb_state *mrb, mrb_value exc)
150 mrb_value str, mesg, file, line;
151 mrb_bool append_mesg;
153 mesg = exc_mesg_get(mrb, mrb_exc_ptr(exc));
154 file = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "file"));
155 line = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "line"));
157 append_mesg = !mrb_nil_p(mesg);
158 if (append_mesg) {
159 mesg = mrb_obj_as_string(mrb, mesg);
160 append_mesg = RSTRING_LEN(mesg) > 0;
163 if (!mrb_nil_p(file) && !mrb_nil_p(line)) {
164 str = mrb_str_dup(mrb, file);
165 mrb_str_cat_lit(mrb, str, ":");
166 mrb_str_append(mrb, str, line);
167 mrb_str_cat_lit(mrb, str, ": ");
168 if (append_mesg) {
169 mrb_str_append(mrb, str, mesg);
170 mrb_str_cat_lit(mrb, str, " (");
172 mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc));
173 if (append_mesg) {
174 mrb_str_cat_lit(mrb, str, ")");
177 else {
178 const char *cname = mrb_obj_classname(mrb, exc);
179 str = mrb_str_new_cstr(mrb, cname);
180 mrb_str_cat_lit(mrb, str, ": ");
181 if (append_mesg) {
182 mrb_str_append(mrb, str, mesg);
184 else {
185 mrb_str_cat_cstr(mrb, str, cname);
188 return str;
192 static void
193 exc_debug_info(mrb_state *mrb, struct RObject *exc)
195 mrb_callinfo *ci = mrb->c->ci;
196 mrb_code *pc = ci->pc;
198 mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "ciidx"), mrb_fixnum_value((mrb_int)(ci - mrb->c->cibase)));
199 while (ci >= mrb->c->cibase) {
200 mrb_code *err = ci->err;
202 if (!err && pc) err = pc - 1;
203 if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
204 mrb_irep *irep = ci->proc->body.irep;
206 int32_t const line = mrb_debug_get_line(irep, (uint32_t)(err - irep->iseq));
207 char const* file = mrb_debug_get_filename(irep, (uint32_t)(err - irep->iseq));
208 if (line != -1 && file) {
209 mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file));
210 mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line));
211 return;
214 pc = ci->pc;
215 ci--;
219 mrb_noreturn void
220 mrb_exc_raise(mrb_state *mrb, mrb_value exc)
222 mrb->exc = mrb_obj_ptr(exc);
223 if (!mrb->out_of_memory) {
224 exc_debug_info(mrb, mrb->exc);
226 if (!mrb->jmp) {
227 mrb_p(mrb, exc);
228 abort();
230 MRB_THROW(mrb->jmp);
233 mrb_noreturn void
234 mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg)
236 mrb_value mesg;
237 mesg = mrb_str_new_cstr(mrb, msg);
238 mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg));
241 mrb_value
242 mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
244 const char *p = format;
245 const char *b = p;
246 ptrdiff_t size;
247 mrb_value ary = mrb_ary_new_capa(mrb, 4);
249 while (*p) {
250 const char c = *p++;
252 if (c == '%') {
253 if (*p == 'S') {
254 size = p - b - 1;
255 mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
256 mrb_ary_push(mrb, ary, va_arg(ap, mrb_value));
257 b = p + 1;
260 else if (c == '\\') {
261 if (*p) {
262 size = p - b - 1;
263 mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
264 mrb_ary_push(mrb, ary, mrb_str_new(mrb, p, 1));
265 b = ++p;
267 else {
268 break;
272 if (b == format) {
273 return mrb_str_new_cstr(mrb, format);
275 else {
276 size = p - b;
277 mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
278 return mrb_ary_join(mrb, ary, mrb_str_new(mrb,NULL,0));
282 mrb_value
283 mrb_format(mrb_state *mrb, const char *format, ...)
285 va_list ap;
286 mrb_value str;
288 va_start(ap, format);
289 str = mrb_vformat(mrb, format, ap);
290 va_end(ap);
292 return str;
295 mrb_noreturn void
296 mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...)
298 va_list args;
299 mrb_value mesg;
301 va_start(args, fmt);
302 mesg = mrb_vformat(mrb, fmt, args);
303 va_end(args);
304 mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg));
307 mrb_noreturn void
308 mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
310 mrb_value exc;
311 mrb_value argv[2];
312 va_list args;
314 va_start(args, fmt);
315 argv[0] = mrb_vformat(mrb, fmt, args);
316 va_end(args);
318 argv[1] = mrb_symbol_value(id);
319 exc = mrb_obj_new(mrb, E_NAME_ERROR, 2, argv);
320 mrb_exc_raise(mrb, exc);
323 void
324 mrb_warn(mrb_state *mrb, const char *fmt, ...)
326 #ifdef ENABLE_STDIO
327 va_list ap;
328 mrb_value str;
330 va_start(ap, fmt);
331 str = mrb_vformat(mrb, fmt, ap);
332 fputs("warning: ", stderr);
333 fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
334 va_end(ap);
335 #endif
338 mrb_noreturn void
339 mrb_bug(mrb_state *mrb, const char *fmt, ...)
341 #ifdef ENABLE_STDIO
342 va_list ap;
343 mrb_value str;
345 va_start(ap, fmt);
346 str = mrb_vformat(mrb, fmt, ap);
347 fputs("bug: ", stderr);
348 fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
349 va_end(ap);
350 #endif
351 exit(EXIT_FAILURE);
354 static void
355 set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt)
357 mrb_funcall(mrb, info, "set_backtrace", 1, bt);
360 static mrb_value
361 make_exception(mrb_state *mrb, int argc, const mrb_value *argv, mrb_bool isstr)
363 mrb_value mesg;
364 int n;
366 mesg = mrb_nil_value();
367 switch (argc) {
368 case 0:
369 break;
370 case 1:
371 if (mrb_nil_p(argv[0]))
372 break;
373 if (isstr) {
374 mesg = mrb_check_string_type(mrb, argv[0]);
375 if (!mrb_nil_p(mesg)) {
376 mesg = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, mesg);
377 break;
380 n = 0;
381 goto exception_call;
383 case 2:
384 case 3:
385 n = 1;
386 exception_call:
388 mrb_sym exc = mrb_intern_lit(mrb, "exception");
389 if (mrb_respond_to(mrb, argv[0], exc)) {
390 mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1);
392 else {
393 /* undef */
394 mrb_raise(mrb, E_TYPE_ERROR, "exception class/object expected");
398 break;
399 default:
400 mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 0..3)", mrb_fixnum_value(argc));
401 break;
403 if (argc > 0) {
404 if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class))
405 mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
406 if (argc > 2)
407 set_backtrace(mrb, mesg, argv[2]);
410 return mesg;
413 mrb_value
414 mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv)
416 return make_exception(mrb, argc, argv, TRUE);
419 void
420 mrb_sys_fail(mrb_state *mrb, const char *mesg)
422 struct RClass *sce;
423 mrb_int no;
425 no = (mrb_int)errno;
426 if (mrb_class_defined(mrb, "SystemCallError")) {
427 sce = mrb_class_get(mrb, "SystemCallError");
428 if (mesg != NULL) {
429 mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 2, mrb_fixnum_value(no), mrb_str_new_cstr(mrb, mesg));
431 else {
432 mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 1, mrb_fixnum_value(no));
435 else {
436 mrb_raise(mrb, E_RUNTIME_ERROR, mesg);
440 mrb_noreturn void
441 mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, char const* fmt, ...)
443 mrb_value exc;
444 va_list ap;
446 va_start(ap, fmt);
447 exc = mrb_funcall(mrb, mrb_obj_value(E_NOMETHOD_ERROR), "new", 3,
448 mrb_vformat(mrb, fmt, ap), mrb_symbol_value(id),
449 mrb_ary_new_from_values(mrb, argc, argv));
450 va_end(ap);
451 mrb_exc_raise(mrb, exc);
454 void
455 mrb_init_exception(mrb_state *mrb)
457 struct RClass *exception, *runtime_error, *script_error;
459 mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
460 MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION);
461 mrb_define_class_method(mrb, exception, "exception", mrb_instance_new, MRB_ARGS_ANY());
462 mrb_define_method(mrb, exception, "exception", exc_exception, MRB_ARGS_ANY());
463 mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_ANY());
464 mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE());
465 mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE());
466 mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE());
467 mrb_define_method(mrb, exception, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE());
469 mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
470 runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
471 mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str(mrb, runtime_error, mrb_str_new_lit(mrb, "Out of memory")));
472 script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */
473 mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */
474 mrb_define_class(mrb, "SystemStackError", exception);