From: "NARUSE, Yui" Date: 2007-06-17T22:23:59+09:00 Subject: [ruby-dev:31015] Re: ("a".."f").step(2) {|x| p x} naruse です。 Yukihiro Matsumoto wrote: > まつもと ゆきひろです > > In message "Re: [ruby-dev:31009] Re: ("a".."f").step(2) {|x| p x}" > on Sat, 16 Jun 2007 12:38:00 +0900, SASADA Koichi writes: > > |> |string の range の step で引数が効かないように思います。 > |> | > |> |% ./ruby -ve '("a".."f").step(2) {|x| p x}' > |> |ruby 1.9.0 (2007-06-15 patchlevel 0) [i686-linux] > |> > |> rb_iterate()になんらかの問題があって、bl_procに渡した関数で > |> はなく、その外側のブロックを直接呼んでしまっているようです。 > |> が、YARV coreの仕組みはよくわからず、それ以上は追えませんで > |> した。 > | > | 問題があるというか、ひとつのスタックフレームには 1 つのブ > |ロック渡ししか対応していません。これは、そんなに変な制限ではな > |いと思います。 > > ごめんなさい。「ひとつのスタックフレームには 1 つのブロック渡 > ししか対応していません」というのがなにを意味するのかよくわか > りません。ので、変な制限でないのかどうかの判断もできません。 > rb_iterate()全般が動かないというわけではないようですが、たと > えばeach_with_indexが動いてstepが動かない理由ってのはすぐに > ピンとは来ませんね。 range_stepの場合 str_step -> step_i -> block でなければいけないのに、 str_step -> block となってしまっているということですかね・・・? 追ってみると、 range_step rb_iterate(str_step, (VALUE)args, step_i, (VALUE)iter); rb_iterate(VALUE (*it_proc) (VALUE), VALUE data1, VALUE (*bl_proc) (ANYARGS), VALUE data2) NODE *node = NEW_IFUNC(bl_proc, data2); blockptr->iseq = (void *)node; th->passed_block = blockptr; retval = (*it_proc) (data1); ... th_call0(rb_thread_t *th, VALUE klass, VALUE recv, VALUE id, ID oid, int argc, const VALUE *argv, NODE * body, int nosuper) if (th->passed_block) { blockptr = th->passed_block; th->passed_block = 0; } push_frame(th, 0, FRAME_MAGIC_CFUNC, recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1); val = call_cfunc(body->nd_cfnc, recv, body->nd_argc, argc, argv); となり、bl_proc がフレームに積まれているように見えて、呼ばれてはいない? どうも完全に rb_iterate が機能していない気がするのですが。 とりあえずは str_step を rb_str_upto と step_i を組み合わせるのでなく、 rb_str_step を使うようにしてみるとかどうでしょう。 Index: string.c =================================================================== --- string.c (revision 12561) +++ string.c (working copy) @@ -1575,7 +1575,38 @@ return beg; } +VALUE +rb_str_step(VALUE beg, VALUE end, int excl, int unit) +{ + VALUE current, after_end; + ID succ = rb_intern("succ"); + int n; + int iter = 1; + StringValue(end); + n = rb_str_cmp(beg, end); + if (n > 0 || (excl && n == 0)) return beg; + after_end = rb_funcall(end, succ, 0, 0); + current = beg; + while (!rb_str_equal(current, after_end)) { + iter--; + if (iter == 0) { + iter = unit; + rb_yield(current); + } + if (!excl && rb_str_equal(current, end)) break; + current = rb_funcall(current, succ, 0, 0); + StringValue(current); + if (excl && rb_str_equal(current, end)) break; + StringValue(current); + if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0) + break; + } + + return beg; +} + + /* * call-seq: * str.upto(other_str) {|s| block } => str Index: range.c =================================================================== --- range.c (revision 12561) +++ range.c (working copy) @@ -223,7 +223,7 @@ { VALUE *args = (VALUE *)arg; - return rb_str_upto(args[0], args[1], EXCL(args[2])); + return rb_str_step(args[0], args[1], EXCL(args[2]), args[3]); } static void @@ -330,9 +330,8 @@ args[0] = b; args[1] = e; args[2] = range; - iter[0] = 1; - iter[1] = unit; - rb_iterate(str_step, (VALUE)args, step_i, (VALUE)iter); + args[3] = unit; + (*str_step)((VALUE)args); } else if (rb_obj_is_kind_of(b, rb_cNumeric)) { ID c = rb_intern(EXCL(range) ? "<" : "<="); -- NARUSE, Yui DBDB A476 FDBD 9450 02CD 0EFC BCE3 C388 472E C1EA