mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Refine output of mrb_print_error()
The following improvements are made according to Ruby's behavior:
- Match location number to index.
- Remove duplicate most recent call output.
- Fix that first call is not output when array (unpacked) backtrace.
### Example
```ruby
def a; raise "error!" end
def b; a end
begin
b
rescue => e
e.backtrace if ARGV[0] == "unpack" # unpack backtrace
raise e
end
```
#### Before this patch:
```
$ bin/mruby example.rb unpack
trace (most recent call last):
[0] example.rb:2:in b
[1] example.rb:1:in a
example.rb:1: error! (RuntimeError)
```
#### After this patch:
```
$ bin/mruby example.rb unpack
trace (most recent call last):
[2] example.rb:4
[1] example.rb:2:in b
example.rb:1:in a: error! (RuntimeError)
```
This commit is contained in:
+28
-43
@@ -25,6 +25,10 @@ typedef void (*each_backtrace_func)(mrb_state*, const struct backtrace_location*
|
||||
|
||||
static const mrb_data_type bt_type = { "Backtrace", mrb_free };
|
||||
|
||||
mrb_value mrb_exc_to_s(mrb_state *mrb, mrb_value exc);
|
||||
mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass);
|
||||
mrb_value mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace);
|
||||
|
||||
static void
|
||||
each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, const mrb_code *pc0, each_backtrace_func func, void *data)
|
||||
{
|
||||
@@ -74,50 +78,35 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, const mrb_code *pc0, each_backtr
|
||||
#ifndef MRB_DISABLE_STDIO
|
||||
|
||||
static void
|
||||
print_backtrace(mrb_state *mrb, mrb_value backtrace)
|
||||
print_backtrace(mrb_state *mrb, struct RObject *exc, mrb_value backtrace)
|
||||
{
|
||||
int i;
|
||||
mrb_int n;
|
||||
mrb_int n = RARRAY_LEN(backtrace);
|
||||
mrb_value *loc, mesg, cname;
|
||||
FILE *stream = stderr;
|
||||
|
||||
n = RARRAY_LEN(backtrace) - 1;
|
||||
if (n == 0) return;
|
||||
|
||||
fprintf(stream, "trace (most recent call last):\n");
|
||||
for (i=0; i<n; i++) {
|
||||
mrb_value entry = RARRAY_PTR(backtrace)[n-i-1];
|
||||
|
||||
if (mrb_string_p(entry)) {
|
||||
fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry));
|
||||
if (n != 0) {
|
||||
fprintf(stream, "trace (most recent call last):\n");
|
||||
for (i=n-1,loc=&RARRAY_PTR(backtrace)[i]; i>0; i--,loc--) {
|
||||
if (mrb_string_p(*loc)) {
|
||||
fprintf(stream, "\t[%d] %.*s\n",
|
||||
i, (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_packed_backtrace(mrb_state *mrb, mrb_value packed)
|
||||
{
|
||||
FILE *stream = stderr;
|
||||
const struct backtrace_location *bt;
|
||||
int n, i;
|
||||
int ai = mrb_gc_arena_save(mrb);
|
||||
|
||||
bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, packed, &bt_type);
|
||||
if (bt == NULL) return;
|
||||
n = (int)RDATA(packed)->flags;
|
||||
if (n == 0) return;
|
||||
|
||||
fprintf(stream, "trace (most recent call last):\n");
|
||||
for (i = 0; i<n; i++) {
|
||||
const struct backtrace_location *entry = &bt[n-i-1];
|
||||
fprintf(stream, "\t[%d] %s:%d", i, entry->filename, (int)entry->lineno);
|
||||
if (entry->method_id != 0) {
|
||||
const char *method_name;
|
||||
|
||||
method_name = mrb_sym_name(mrb, entry->method_id);
|
||||
fprintf(stream, ":in %s", method_name);
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
}
|
||||
fprintf(stream, "\n");
|
||||
if (n != 0) {
|
||||
fprintf(stream, "%.*s: ", (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc));
|
||||
}
|
||||
mesg = mrb_exc_to_s(mrb, mrb_obj_value(exc));
|
||||
cname = mrb_mod_to_s(mrb, mrb_obj_value(exc->c));
|
||||
if (RSTRING_LEN(mesg) == 0) {
|
||||
fprintf(stream, "%.*s \n", (int)RSTRING_LEN(cname), RSTRING_PTR(cname));
|
||||
}
|
||||
else {
|
||||
fprintf(stream, "%.*s (%.*s)\n",
|
||||
(int)RSTRING_LEN(mesg), RSTRING_PTR(mesg),
|
||||
(int)RSTRING_LEN(cname), RSTRING_PTR(cname));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,12 +126,8 @@ mrb_print_backtrace(mrb_state *mrb)
|
||||
|
||||
backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace"));
|
||||
if (mrb_nil_p(backtrace)) return;
|
||||
if (mrb_array_p(backtrace)) {
|
||||
print_backtrace(mrb, backtrace);
|
||||
}
|
||||
else {
|
||||
print_packed_backtrace(mrb, backtrace);
|
||||
}
|
||||
if (!mrb_array_p(backtrace)) backtrace = mrb_unpack_backtrace(mrb, backtrace);
|
||||
print_backtrace(mrb, mrb->exc, backtrace);
|
||||
}
|
||||
#else
|
||||
|
||||
|
||||
+3
-3
@@ -88,8 +88,8 @@ exc_exception(mrb_state *mrb, mrb_value self)
|
||||
* no message is set).
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
exc_to_s(mrb_state *mrb, mrb_value exc)
|
||||
mrb_value
|
||||
mrb_exc_to_s(mrb_state *mrb, mrb_value exc)
|
||||
{
|
||||
mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
|
||||
struct RObject *p;
|
||||
@@ -596,7 +596,7 @@ mrb_init_exception(mrb_state *mrb)
|
||||
mrb_define_class_method(mrb, exception, "exception", mrb_instance_new, MRB_ARGS_OPT(1));
|
||||
mrb_define_method(mrb, exception, "exception", exc_exception, MRB_ARGS_OPT(1));
|
||||
mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_OPT(1));
|
||||
mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, exception, "to_s", mrb_exc_to_s, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, exception, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE());
|
||||
|
||||
@@ -31,7 +31,6 @@ MRB_API void
|
||||
mrb_print_error(mrb_state *mrb)
|
||||
{
|
||||
mrb_print_backtrace(mrb);
|
||||
printstr(mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0), stderr);
|
||||
}
|
||||
|
||||
MRB_API void
|
||||
|
||||
Reference in New Issue
Block a user