diff --git a/ChangeLog b/ChangeLog index 32d53da55c..415e99ca5b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Sun Nov 16 04:41:33 2003 Yukihiro Matsumoto + + * eval.c (eval): do not re-raise exception to avoid unnecessary + exception copying, instead modify exception and internal + information to adjust eval(). + + * eval.c (backtrace): can return the current frame information + only if lev < -1. + Sat Nov 15 22:16:42 2003 GOTOU Yuuzou * /ext/openssl/ossl_x509ext.c (ossl_x509extfactory_create_ext): diff --git a/error.c b/error.c index 2baf3b1ba7..b5b14decae 100644 --- a/error.c +++ b/error.c @@ -479,8 +479,9 @@ name_err_initialize(argc, argv, self) VALUE *argv; VALUE self; { - VALUE name = (argc > 1) ? argv[--argc] : Qnil; + VALUE name; + name = (argc > 1) ? argv[--argc] : Qnil; exc_initialize(argc, argv, self); rb_iv_set(self, "name", name); return self; diff --git a/eval.c b/eval.c index 64fa28bd98..4d3fd66b7f 100644 --- a/eval.c +++ b/eval.c @@ -1328,7 +1328,6 @@ void rb_exec_end_proc _((void)); static void ruby_finalize_0() { - ruby_errinfo = 0; PUSH_TAG(PROT_NONE); if (EXEC_TAG() == 0) { rb_trap_exit(); @@ -4719,6 +4718,58 @@ static int last_call_status; #define CSTAT_VCALL 4 #define CSTAT_SUPER 8 +static VALUE +name_err_to_s(exc) + VALUE exc; +{ + VALUE mesg = rb_attr_get(exc, rb_intern("mesg")); + ID id_recv = rb_intern("recv"); + + if (NIL_P(mesg)) return rb_class_path(CLASS_OF(exc)); + if (rb_ivar_defined(exc, id_recv)) { + char buf[BUFSIZ]; + char *desc = ""; + volatile VALUE d = 0; + int noclass; + VALUE obj = rb_ivar_get(exc, id_recv); + int state; + + switch (TYPE(obj)) { + case T_NIL: + desc = "nil"; + break; + case T_TRUE: + desc = "true"; + break; + case T_FALSE: + desc = "false"; + break; + default: + PUSH_TAG(PROT_NONE); + if ((state = EXEC_TAG()) == 0) { + d = rb_inspect(obj); + } + POP_TAG(); + if (!d || RSTRING(d)->len > 65) { + d = rb_any_to_s(obj); + } + break; + } + if (d) { + desc = RSTRING(d)->ptr; + } + noclass = (!desc || desc[0]=='#'); + snprintf(buf, BUFSIZ, RSTRING(mesg)->ptr, desc, + noclass ? "" : ":", + noclass ? "" : rb_obj_classname(obj)); + mesg = rb_str_new2(buf); + rb_iv_set(exc, "mesg", mesg); + st_delete(ROBJECT(exc)->iv_tbl, (st_data_t*)&id_recv, 0); + } + if (OBJ_TAINTED(exc)) OBJ_TAINT(mesg); + return mesg; +} + static VALUE rb_method_missing(argc, argv, obj) int argc; @@ -4727,11 +4778,8 @@ rb_method_missing(argc, argv, obj) { ID id; VALUE exc = rb_eNoMethodError; - volatile VALUE d = 0; char *format = 0; - char *desc = ""; NODE *cnode = ruby_current_node; - int state; if (argc == 0 || !SYMBOL_P(argv[0])) { rb_raise(rb_eArgError, "no id given"); @@ -4741,64 +4789,37 @@ rb_method_missing(argc, argv, obj) id = SYM2ID(argv[0]); - switch (TYPE(obj)) { - case T_NIL: - desc = "nil"; - break; - case T_TRUE: - desc = "true"; - break; - case T_FALSE: - desc = "false"; - break; - default: - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - d = rb_inspect(obj); - } - POP_TAG(); - if (!d || RSTRING(d)->len > 65) { - d = rb_any_to_s(obj); - } - break; - } - if (d) { - desc = RSTRING(d)->ptr; - } - if (last_call_status & CSTAT_PRIV) { - format = "private method `%s' called for %s%s%s"; + format = "private method `%s' called for %%s%%s%%s"; } else if (last_call_status & CSTAT_PROT) { - format = "protected method `%s' called for %s%s%s"; + format = "protected method `%s' called for %%s%%s%%s"; } else if (last_call_status & CSTAT_VCALL) { - format = "undefined local variable or method `%s' for %s%s%s"; + format = "undefined local variable or method `%s' for %%s%%s%%s"; exc = rb_eNameError; } else if (last_call_status & CSTAT_SUPER) { format = "super: no superclass method `%s'"; } if (!format) { - format = "undefined method `%s' for %s%s%s"; + format = "undefined method `%s' for %%s%%s%%s"; } ruby_current_node = cnode; { char buf[BUFSIZ]; - int noclass = (!desc || desc[0]=='#'); int n = 0; VALUE args[3]; - snprintf(buf, BUFSIZ, format, rb_id2name(id), - desc, noclass ? "" : ":", - noclass ? "" : rb_obj_classname(obj)); + snprintf(buf, BUFSIZ, format, rb_id2name(id)); args[n++] = rb_str_new2(buf); args[n++] = argv[0]; if (exc == rb_eNoMethodError) { args[n++] = rb_ary_new4(argc-1, argv+1); } exc = rb_class_new_instance(n, args, exc); + rb_iv_set(exc, "recv", obj); ruby_frame = ruby_frame->prev; /* pop frame for "method_missing" */ rb_exc_raise(exc); } @@ -5357,6 +5378,7 @@ backtrace(lev) snprintf(buf, BUFSIZ, "%s:%d", ruby_sourcefile, ruby_sourceline); } rb_ary_push(ary, rb_str_new2(buf)); + if (lev < -1) return ary; } else { while (lev-- > 0) { @@ -5557,20 +5579,13 @@ eval(self, src, scope, file, line) ruby_set_current_source(); if (state) { if (state == TAG_RAISE) { - VALUE err, errat, mesg; - - mesg = rb_obj_as_string(ruby_errinfo); if (strcmp(file, "(eval)") == 0) { - if (ruby_sourceline > 1) { - errat = get_backtrace(ruby_errinfo); - err = rb_str_dup(RARRAY(errat)->ptr[0]); - rb_str_cat2(err, ": "); - rb_str_append(err, mesg); - } - else { - err = mesg; - } - rb_exc_raise(rb_funcall(ruby_errinfo, rb_intern("exception"), 1, err)); + VALUE mesg, errat; + + errat = get_backtrace(ruby_errinfo); + mesg = rb_obj_as_string(ruby_errinfo); + rb_str_update(mesg, 0, 0, RARRAY(errat)->ptr[0]); + RARRAY(errat)->ptr[0] = RARRAY(backtrace(-2))->ptr[0]; } rb_exc_raise(ruby_errinfo); } @@ -6757,6 +6772,9 @@ Init_load() ruby_dln_librefs = rb_ary_new(); rb_global_variable(&ruby_dln_librefs); + + /* not really a right place */ + rb_define_method(rb_eNameError, "to_s", name_err_to_s, 0); } static void