eval_error.c

Go to the documentation of this file.
00001 /* -*-c-*- */
00002 /*
00003  * included by eval.c
00004  */
00005 
00006 static void
00007 warn_printf(const char *fmt, ...)
00008 {
00009     VALUE str;
00010     va_list args;
00011 
00012     va_init_list(args, fmt);
00013     str = rb_vsprintf(fmt, args);
00014     va_end(args);
00015     rb_write_error_str(str);
00016 }
00017 
00018 #define warn_print(x) rb_write_error(x)
00019 #define warn_print2(x,l) rb_write_error2((x),(l))
00020 #define warn_print_str(x) rb_write_error_str(x)
00021 
00022 static void
00023 error_pos(void)
00024 {
00025     const char *sourcefile = rb_sourcefile();
00026     int sourceline = rb_sourceline();
00027 
00028     if (sourcefile) {
00029         ID caller_name;
00030         if (sourceline == 0) {
00031             warn_printf("%s", sourcefile);
00032         }
00033         else if ((caller_name = rb_frame_callee()) != 0) {
00034             warn_printf("%s:%d:in `%s'", sourcefile, sourceline,
00035                         rb_id2name(caller_name));
00036         }
00037         else {
00038             warn_printf("%s:%d", sourcefile, sourceline);
00039         }
00040     }
00041 }
00042 
00043 static VALUE
00044 get_backtrace(VALUE info)
00045 {
00046     if (NIL_P(info))
00047         return Qnil;
00048     info = rb_funcall(info, rb_intern("backtrace"), 0);
00049     if (NIL_P(info))
00050         return Qnil;
00051     return rb_check_backtrace(info);
00052 }
00053 
00054 VALUE
00055 rb_get_backtrace(VALUE info)
00056 {
00057     return get_backtrace(info);
00058 }
00059 
00060 VALUE rb_exc_set_backtrace(VALUE exc, VALUE bt);
00061 
00062 static void
00063 set_backtrace(VALUE info, VALUE bt)
00064 {
00065     ID set_backtrace = rb_intern("set_backtrace");
00066 
00067     if (rb_backtrace_p(bt)) {
00068         if (rb_method_basic_definition_p(CLASS_OF(info), set_backtrace)) {
00069             rb_exc_set_backtrace(info, bt);
00070             return;
00071         }
00072         else {
00073             bt = rb_backtrace_to_str_ary(bt);
00074         }
00075     }
00076     rb_funcall(info, rb_intern("set_backtrace"), 1, bt);
00077 }
00078 
00079 static void
00080 error_print(void)
00081 {
00082     volatile VALUE errat = Qundef;
00083     rb_thread_t *th = GET_THREAD();
00084     VALUE errinfo = th->errinfo;
00085     int raised_flag = th->raised_flag;
00086     volatile VALUE eclass = Qundef, e = Qundef;
00087     const char *volatile einfo;
00088     volatile long elen;
00089 
00090     if (NIL_P(errinfo))
00091         return;
00092     rb_thread_raised_clear(th);
00093 
00094     TH_PUSH_TAG(th);
00095     if (TH_EXEC_TAG() == 0) {
00096         errat = get_backtrace(errinfo);
00097     }
00098     else if (errat == Qundef) {
00099         errat = Qnil;
00100     }
00101     else if (eclass == Qundef || e != Qundef) {
00102         goto error;
00103     }
00104     else {
00105         goto no_message;
00106     }
00107     if (NIL_P(errat)) {
00108         const char *file = rb_sourcefile();
00109         int line = rb_sourceline();
00110         if (!file)
00111             warn_printf("%d", line);
00112         else if (!line)
00113             warn_printf("%s", file);
00114         else
00115             warn_printf("%s:%d", file, line);
00116     }
00117     else if (RARRAY_LEN(errat) == 0) {
00118         error_pos();
00119     }
00120     else {
00121         VALUE mesg = RARRAY_AREF(errat, 0);
00122 
00123         if (NIL_P(mesg))
00124             error_pos();
00125         else {
00126             warn_print_str(mesg);
00127         }
00128     }
00129 
00130     eclass = CLASS_OF(errinfo);
00131     if (eclass != Qundef &&
00132         (e = rb_check_funcall(errinfo, rb_intern("message"), 0, 0)) != Qundef &&
00133         (RB_TYPE_P(e, T_STRING) || !NIL_P(e = rb_check_string_type(e)))) {
00134         einfo = RSTRING_PTR(e);
00135         elen = RSTRING_LEN(e);
00136     }
00137     else {
00138       no_message:
00139         einfo = "";
00140         elen = 0;
00141     }
00142     if (eclass == rb_eRuntimeError && elen == 0) {
00143         warn_print(": unhandled exception\n");
00144     }
00145     else {
00146         VALUE epath;
00147 
00148         epath = rb_class_name(eclass);
00149         if (elen == 0) {
00150             warn_print(": ");
00151             warn_print_str(epath);
00152             warn_print("\n");
00153         }
00154         else {
00155             char *tail = 0;
00156             long len = elen;
00157 
00158             if (RSTRING_PTR(epath)[0] == '#')
00159                 epath = 0;
00160             if ((tail = memchr(einfo, '\n', elen)) != 0) {
00161                 len = tail - einfo;
00162                 tail++;         /* skip newline */
00163             }
00164             warn_print(": ");
00165             warn_print2(einfo, len);
00166             if (epath) {
00167                 warn_print(" (");
00168                 warn_print_str(epath);
00169                 warn_print(")\n");
00170             }
00171             if (tail) {
00172                 warn_print2(tail, elen - len - 1);
00173                 if (einfo[elen-1] != '\n') warn_print2("\n", 1);
00174             }
00175         }
00176     }
00177 
00178     if (!NIL_P(errat)) {
00179         long i;
00180         long len = RARRAY_LEN(errat);
00181         int skip = eclass == rb_eSysStackError;
00182 
00183 #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
00184 #define TRACE_HEAD 8
00185 #define TRACE_TAIL 5
00186 
00187         for (i = 1; i < len; i++) {
00188             VALUE line = RARRAY_AREF(errat, i);
00189             if (RB_TYPE_P(line, T_STRING)) {
00190                 warn_printf("\tfrom %"PRIsVALUE"\n", line);
00191             }
00192             if (skip && i == TRACE_HEAD && len > TRACE_MAX) {
00193                 warn_printf("\t ... %ld levels...\n",
00194                             len - TRACE_HEAD - TRACE_TAIL);
00195                 i = len - TRACE_TAIL;
00196             }
00197         }
00198     }
00199   error:
00200     TH_POP_TAG();
00201     th->errinfo = errinfo;
00202     rb_thread_raised_set(th, raised_flag);
00203 }
00204 
00205 void
00206 ruby_error_print(void)
00207 {
00208     error_print();
00209 }
00210 
00211 void
00212 rb_print_undef(VALUE klass, ID id, int scope)
00213 {
00214     const char *v;
00215 
00216     switch (scope) {
00217       default:
00218       case NOEX_PUBLIC: v = ""; break;
00219       case NOEX_PRIVATE: v = " private"; break;
00220       case NOEX_PROTECTED: v = " protected"; break;
00221     }
00222     rb_name_error(id, "undefined%s method `%"PRIsVALUE"' for %s `%"PRIsVALUE"'", v,
00223                   QUOTE_ID(id),
00224                   (RB_TYPE_P(klass, T_MODULE)) ? "module" : "class",
00225                   rb_class_name(klass));
00226 }
00227 
00228 void
00229 rb_print_undef_str(VALUE klass, VALUE name)
00230 {
00231     rb_name_error_str(name, "undefined method `%"PRIsVALUE"' for %s `%"PRIsVALUE"'",
00232                       QUOTE(name),
00233                       (RB_TYPE_P(klass, T_MODULE)) ? "module" : "class",
00234                       rb_class_name(klass));
00235 }
00236 
00237 static int
00238 sysexit_status(VALUE err)
00239 {
00240     VALUE st = rb_iv_get(err, "status");
00241     return NUM2INT(st);
00242 }
00243 
00244 static int
00245 error_handle(int ex)
00246 {
00247     int status = EXIT_FAILURE;
00248     rb_thread_t *th = GET_THREAD();
00249 
00250     if (rb_threadptr_set_raised(th))
00251         return EXIT_FAILURE;
00252     switch (ex & TAG_MASK) {
00253       case 0:
00254         status = EXIT_SUCCESS;
00255         break;
00256 
00257       case TAG_RETURN:
00258         error_pos();
00259         warn_print(": unexpected return\n");
00260         break;
00261       case TAG_NEXT:
00262         error_pos();
00263         warn_print(": unexpected next\n");
00264         break;
00265       case TAG_BREAK:
00266         error_pos();
00267         warn_print(": unexpected break\n");
00268         break;
00269       case TAG_REDO:
00270         error_pos();
00271         warn_print(": unexpected redo\n");
00272         break;
00273       case TAG_RETRY:
00274         error_pos();
00275         warn_print(": retry outside of rescue clause\n");
00276         break;
00277       case TAG_THROW:
00278         /* TODO: fix me */
00279         error_pos();
00280         warn_printf(": unexpected throw\n");
00281         break;
00282       case TAG_RAISE: {
00283         VALUE errinfo = GET_THREAD()->errinfo;
00284         if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
00285             status = sysexit_status(errinfo);
00286         }
00287         else if (rb_obj_is_instance_of(errinfo, rb_eSignal)) {
00288             /* no message when exiting by signal */
00289         }
00290         else {
00291             error_print();
00292         }
00293         break;
00294       }
00295       case TAG_FATAL:
00296         error_print();
00297         break;
00298       default:
00299         rb_bug("Unknown longjmp status %d", ex);
00300         break;
00301     }
00302     rb_threadptr_reset_raised(th);
00303     return status;
00304 }
00305 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7