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