sabme ua / mruby-mbed

Dependents:   mruby_mbed_web mirb_mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers error.c Source File

error.c

00001 /*
00002 ** error.c - Exception class
00003 **
00004 ** See Copyright Notice in mruby.h
00005 */
00006 
00007 #include <errno.h>
00008 #include <stdarg.h>
00009 #include <stdlib.h>
00010 #include "mruby.h"
00011 #include "mruby/array.h"
00012 #include "mruby/irep.h"
00013 #include "mruby/proc.h"
00014 #include "mruby/string.h"
00015 #include "mruby/variable.h"
00016 #include "mruby/debug.h"
00017 #include "mruby/error.h"
00018 #include "mruby/class.h"
00019 #include "mrb_throw.h"
00020 
00021 MRB_API mrb_value
00022 mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len)
00023 {
00024   mrb_value arg = mrb_str_new(mrb, ptr, len);
00025   return mrb_obj_new(mrb, c, 1, &arg);
00026 }
00027 
00028 MRB_API mrb_value
00029 mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str)
00030 {
00031   str = mrb_str_to_str(mrb, str);
00032   return mrb_obj_new(mrb, c, 1, &str);
00033 }
00034 
00035 /*
00036  * call-seq:
00037  *    Exception.new(msg = nil)   ->  exception
00038  *
00039  *  Construct a new Exception object, optionally passing in
00040  *  a message.
00041  */
00042 
00043 static mrb_value
00044 exc_initialize(mrb_state *mrb, mrb_value exc)
00045 {
00046   mrb_value mesg;
00047 
00048   if (mrb_get_args(mrb, "|o", &mesg) == 1) {
00049     mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg);
00050   }
00051   return exc;
00052 }
00053 
00054 /*
00055  *  Document-method: exception
00056  *
00057  *  call-seq:
00058  *     exc.exception(string)  ->  an_exception or exc
00059  *
00060  *  With no argument, or if the argument is the same as the receiver,
00061  *  return the receiver. Otherwise, create a new
00062  *  exception object of the same class as the receiver, but with a
00063  *  message equal to <code>string.to_str</code>.
00064  *
00065  */
00066 
00067 static mrb_value
00068 exc_exception(mrb_state *mrb, mrb_value self)
00069 {
00070   mrb_value exc;
00071   mrb_value a;
00072   int argc;
00073 
00074   argc = mrb_get_args(mrb, "|o", &a);
00075   if (argc == 0) return self;
00076   if (mrb_obj_equal(mrb, self, a)) return self;
00077   exc = mrb_obj_clone(mrb, self);
00078   mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), a);
00079 
00080   return exc;
00081 }
00082 
00083 /*
00084  * call-seq:
00085  *   exception.to_s   ->  string
00086  *
00087  * Returns exception's message (or the name of the exception if
00088  * no message is set).
00089  */
00090 
00091 static mrb_value
00092 exc_to_s(mrb_state *mrb, mrb_value exc)
00093 {
00094   mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
00095   struct RObject *p;
00096 
00097   if (!mrb_string_p(mesg)) {
00098     return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
00099   }
00100   p = mrb_obj_ptr(mesg);
00101   if (!p->c) {
00102     p->c = mrb->string_class;
00103   }
00104   return mesg;
00105 }
00106 
00107 /*
00108  * call-seq:
00109  *   exception.message   ->  string
00110  *
00111  * Returns the result of invoking <code>exception.to_s</code>.
00112  * Normally this returns the exception's message or name. By
00113  * supplying a to_str method, exceptions are agreeing to
00114  * be used where Strings are expected.
00115  */
00116 
00117 static mrb_value
00118 exc_message(mrb_state *mrb, mrb_value exc)
00119 {
00120   return mrb_funcall(mrb, exc, "to_s", 0);
00121 }
00122 
00123 /*
00124  * call-seq:
00125  *   exception.inspect   -> string
00126  *
00127  * Returns this exception's file name, line number,
00128  * message and class name.
00129  * If file name or line number is not set,
00130  * returns message and class name.
00131  */
00132 
00133 static mrb_value
00134 exc_inspect(mrb_state *mrb, mrb_value exc)
00135 {
00136   mrb_value str, mesg, file, line;
00137   mrb_bool append_mesg;
00138 
00139   mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
00140   file = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "file"));
00141   line = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "line"));
00142 
00143   append_mesg = !mrb_nil_p(mesg);
00144   if (append_mesg) {
00145     mesg = mrb_obj_as_string(mrb, mesg);
00146     append_mesg = RSTRING_LEN(mesg) > 0;
00147   }
00148 
00149   if (!mrb_nil_p(file) && !mrb_nil_p(line)) {
00150     str = mrb_str_dup(mrb, file);
00151     mrb_str_cat_lit(mrb, str, ":");
00152     mrb_str_append(mrb, str, line);
00153     mrb_str_cat_lit(mrb, str, ": ");
00154     if (append_mesg) {
00155       mrb_str_append(mrb, str, mesg);
00156       mrb_str_cat_lit(mrb, str, " (");
00157     }
00158     mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc));
00159     if (append_mesg) {
00160       mrb_str_cat_lit(mrb, str, ")");
00161     }
00162   }
00163   else {
00164     const char *cname = mrb_obj_classname(mrb, exc);
00165     str = mrb_str_new_cstr(mrb, cname);
00166     mrb_str_cat_lit(mrb, str, ": ");
00167     if (append_mesg) {
00168       mrb_str_append(mrb, str, mesg);
00169     }
00170     else {
00171       mrb_str_cat_cstr(mrb, str, cname);
00172     }
00173   }
00174   return str;
00175 }
00176 
00177 
00178 static void
00179 exc_debug_info(mrb_state *mrb, struct RObject *exc)
00180 {
00181   mrb_callinfo *ci = mrb->c->ci;
00182   mrb_code *pc = ci->pc;
00183 
00184   mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "ciidx"), mrb_fixnum_value((mrb_int)(ci - mrb->c->cibase)));
00185   while (ci >= mrb->c->cibase) {
00186     mrb_code *err = ci->err;
00187 
00188     if (!err && pc) err = pc - 1;
00189     if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
00190       mrb_irep *irep = ci->proc->body.irep;
00191 
00192       int32_t const line = mrb_debug_get_line(irep, (uint32_t)(err - irep->iseq));
00193       char const* file = mrb_debug_get_filename(irep, (uint32_t)(err - irep->iseq));
00194       if (line != -1 && file) {
00195         mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file));
00196         mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line));
00197         return;
00198       }
00199     }
00200     pc = ci->pc;
00201     ci--;
00202   }
00203 }
00204 
00205 MRB_API mrb_noreturn void
00206 mrb_exc_raise(mrb_state *mrb, mrb_value exc)
00207 {
00208   mrb->exc = mrb_obj_ptr(exc);
00209   if (!mrb->out_of_memory) {
00210     exc_debug_info(mrb, mrb->exc);
00211   }
00212   if (!mrb->jmp) {
00213     mrb_p(mrb, exc);
00214     abort();
00215   }
00216   MRB_THROW(mrb->jmp);
00217 }
00218 
00219 MRB_API mrb_noreturn void
00220 mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg)
00221 {
00222   mrb_value mesg;
00223   mesg = mrb_str_new_cstr(mrb, msg);
00224   mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg));
00225 }
00226 
00227 MRB_API mrb_value
00228 mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
00229 {
00230   const char *p = format;
00231   const char *b = p;
00232   ptrdiff_t size;
00233   mrb_value ary = mrb_ary_new_capa(mrb, 4);
00234 
00235   while (*p) {
00236     const char c = *p++;
00237 
00238     if (c == '%') {
00239       if (*p == 'S') {
00240         size = p - b - 1;
00241         mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
00242         mrb_ary_push(mrb, ary, va_arg(ap, mrb_value));
00243         b = p + 1;
00244       }
00245     }
00246     else if (c == '\\') {
00247       if (*p) {
00248         size = p - b - 1;
00249         mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
00250         mrb_ary_push(mrb, ary, mrb_str_new(mrb, p, 1));
00251         b = ++p;
00252       }
00253       else {
00254         break;
00255       }
00256     }
00257   }
00258   if (b == format) {
00259     return mrb_str_new_cstr(mrb, format);
00260   }
00261   else {
00262     size = p - b;
00263     mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
00264     return mrb_ary_join(mrb, ary, mrb_str_new(mrb, NULL, 0));
00265   }
00266 }
00267 
00268 MRB_API mrb_value
00269 mrb_format(mrb_state *mrb, const char *format, ...)
00270 {
00271   va_list ap;
00272   mrb_value str;
00273 
00274   va_start(ap, format);
00275   str = mrb_vformat(mrb, format, ap);
00276   va_end(ap);
00277 
00278   return str;
00279 }
00280 
00281 MRB_API mrb_noreturn void
00282 mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...)
00283 {
00284   va_list args;
00285   mrb_value mesg;
00286 
00287   va_start(args, fmt);
00288   mesg = mrb_vformat(mrb, fmt, args);
00289   va_end(args);
00290   mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg));
00291 }
00292 
00293 MRB_API mrb_noreturn void
00294 mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
00295 {
00296   mrb_value exc;
00297   mrb_value argv[2];
00298   va_list args;
00299 
00300   va_start(args, fmt);
00301   argv[0] = mrb_vformat(mrb, fmt, args);
00302   va_end(args);
00303 
00304   argv[1] = mrb_symbol_value(id);
00305   exc = mrb_obj_new(mrb, E_NAME_ERROR, 2, argv);
00306   mrb_exc_raise(mrb, exc);
00307 }
00308 
00309 MRB_API void
00310 mrb_warn(mrb_state *mrb, const char *fmt, ...)
00311 {
00312 #ifdef ENABLE_STDIO
00313   va_list ap;
00314   mrb_value str;
00315 
00316   va_start(ap, fmt);
00317   str = mrb_vformat(mrb, fmt, ap);
00318   fputs("warning: ", stderr);
00319   fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
00320   va_end(ap);
00321 #endif
00322 }
00323 
00324 MRB_API mrb_noreturn void
00325 mrb_bug(mrb_state *mrb, const char *fmt, ...)
00326 {
00327 #ifdef ENABLE_STDIO
00328   va_list ap;
00329   mrb_value str;
00330 
00331   va_start(ap, fmt);
00332   str = mrb_vformat(mrb, fmt, ap);
00333   fputs("bug: ", stderr);
00334   fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
00335   va_end(ap);
00336 #endif
00337   exit(EXIT_FAILURE);
00338 }
00339 
00340 static void
00341 set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt)
00342 {
00343   mrb_funcall(mrb, info, "set_backtrace", 1, bt);
00344 }
00345 
00346 static mrb_value
00347 make_exception(mrb_state *mrb, int argc, const mrb_value *argv, mrb_bool isstr)
00348 {
00349   mrb_value mesg;
00350   int n;
00351 
00352   mesg = mrb_nil_value();
00353   switch (argc) {
00354     case 0:
00355     break;
00356     case 1:
00357       if (mrb_nil_p(argv[0]))
00358         break;
00359       if (isstr) {
00360         mesg = mrb_check_string_type(mrb, argv[0]);
00361         if (!mrb_nil_p(mesg)) {
00362           mesg = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, mesg);
00363           break;
00364         }
00365       }
00366       n = 0;
00367       goto exception_call;
00368 
00369     case 2:
00370     case 3:
00371       n = 1;
00372 exception_call:
00373       {
00374         mrb_sym exc = mrb_intern_lit(mrb, "exception");
00375         if (mrb_respond_to(mrb, argv[0], exc)) {
00376           mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1);
00377         }
00378         else {
00379           /* undef */
00380           mrb_raise(mrb, E_TYPE_ERROR, "exception class/object expected");
00381         }
00382       }
00383 
00384       break;
00385     default:
00386       mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 0..3)", mrb_fixnum_value(argc));
00387       break;
00388   }
00389   if (argc > 0) {
00390     if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class))
00391       mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
00392     if (argc > 2)
00393         set_backtrace(mrb, mesg, argv[2]);
00394   }
00395 
00396   return mesg;
00397 }
00398 
00399 MRB_API mrb_value
00400 mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv)
00401 {
00402   return make_exception(mrb, argc, argv, TRUE);
00403 }
00404 
00405 MRB_API void
00406 mrb_sys_fail(mrb_state *mrb, const char *mesg)
00407 {
00408   struct RClass *sce;
00409   mrb_int no;
00410 
00411   no = (mrb_int)errno;
00412   if (mrb_class_defined(mrb, "SystemCallError")) {
00413     sce = mrb_class_get(mrb, "SystemCallError");
00414     if (mesg != NULL) {
00415       mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 2, mrb_fixnum_value(no), mrb_str_new_cstr(mrb, mesg));
00416     }
00417     else {
00418       mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 1, mrb_fixnum_value(no));
00419     }
00420   }
00421   else {
00422     mrb_raise(mrb, E_RUNTIME_ERROR, mesg);
00423   }
00424 }
00425 
00426 MRB_API mrb_noreturn void
00427 mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, char const* fmt, ...)
00428 {
00429   mrb_value exc;
00430   va_list ap;
00431 
00432   va_start(ap, fmt);
00433   exc = mrb_funcall(mrb, mrb_obj_value(E_NOMETHOD_ERROR), "new", 3,
00434                     mrb_vformat(mrb, fmt, ap), mrb_symbol_value(id),
00435                     mrb_ary_new_from_values(mrb, argc, argv));
00436   va_end(ap);
00437   mrb_exc_raise(mrb, exc);
00438 }
00439 
00440 void
00441 mrb_init_exception(mrb_state *mrb)
00442 {
00443   struct RClass *exception, *runtime_error, *script_error;
00444 
00445   mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
00446   MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION);
00447   mrb_define_class_method(mrb, exception, "exception", mrb_instance_new,  MRB_ARGS_ANY());
00448   mrb_define_method(mrb, exception, "exception",       exc_exception,     MRB_ARGS_ANY());
00449   mrb_define_method(mrb, exception, "initialize",      exc_initialize,    MRB_ARGS_ANY());
00450   mrb_define_method(mrb, exception, "to_s",            exc_to_s,          MRB_ARGS_NONE());
00451   mrb_define_method(mrb, exception, "message",         exc_message,       MRB_ARGS_NONE());
00452   mrb_define_method(mrb, exception, "inspect",         exc_inspect,       MRB_ARGS_NONE());
00453   mrb_define_method(mrb, exception, "backtrace",       mrb_exc_backtrace, MRB_ARGS_NONE());
00454 
00455   mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
00456   runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class);          /* 15.2.28 */
00457   mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str(mrb, runtime_error, mrb_str_new_lit(mrb, "Out of memory")));
00458   script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class);                /* 15.2.37 */
00459   mrb_define_class(mrb, "SyntaxError", script_error);                                        /* 15.2.38 */
00460   mrb_define_class(mrb, "SystemStackError", exception);
00461 }
00462