From: Robert Feldt Date: 2001-03-06T19:24:09+09:00 Subject: [ruby-talk:12111] Re: RCR: replacing 'caller' On Tue, 6 Mar 2001, Avi Bryant wrote: > Nice... this is, of course, exactly what we needed to be able to play with > dispatchers in pure ruby. > > However, it needs some error checking: > > class Foo > define_method(:x) {puts call_stack[0]} > end > > Foo.new.x #=> SEGFAULT > > I can work around it for new by using call_stack(2)... > Problem is that last_func is 0 when block called. New diff (from original in latest snapshot) that should work better is below. However, I return nil instead of a method when a block. Maybe should return the block instead? Dunno... /Robert --- eval.c.orig Tue Mar 6 06:00:04 2001 +++ eval.c Tue Mar 6 11:16:36 2001 @@ -4687,6 +4687,58 @@ } static VALUE +call_stack(lev) + int lev; +{ + struct FRAME *frame = ruby_frame; + VALUE ary = rb_ary_new(); + VALUE inner_ary; + + while (lev-- > 0) { + frame = frame->prev; + if (!frame) { + ary = Qnil; + break; + } + } + while (frame && frame->file) { + inner_ary = rb_ary_new(); + rb_ary_push(inner_ary, frame->self); + if(frame->last_func == 0) + rb_ary_push(inner_ary, Qnil); + else { + rb_ary_push(inner_ary, ID2SYM(frame->last_func)); + } + rb_ary_push(inner_ary, rb_ary_new4(frame->argc, frame->argv)); + rb_ary_push(inner_ary, rb_str_new2(frame->file)); + rb_ary_push(inner_ary, INT2FIX(frame->line)); + // Add block if block_given? ie. check iter stack and traverse block + // stack accordingly... + rb_ary_push(ary, inner_ary); + frame = frame->prev; + } + + return ary; +} + +static VALUE +rb_f_call_stack(argc, argv) + int argc; + VALUE *argv; +{ + VALUE level; + int lev; + + rb_scan_args(argc, argv, "01", &level); + + if (NIL_P(level)) lev = 1; + else lev = NUM2INT(level); + if (lev < 0) rb_raise(rb_eArgError, "negative level(%d)", lev); + + return call_stack(lev); +} + +static VALUE rb_f_caller(argc, argv) int argc; VALUE *argv; @@ -5869,6 +5921,7 @@ rb_define_global_function("fail", rb_f_raise, -1); rb_define_global_function("caller", rb_f_caller, -1); + rb_define_global_function("call_stack", rb_f_call_stack, -1); rb_define_global_function("exit", rb_f_exit, -1); rb_define_global_function("abort", rb_f_abort, 0);