From: Kazuhiro HIWADA Date: 1998-11-28T01:17:10+09:00 Subject: [ruby-dev:3690] Re: nested method? (Re: block local variable) ひわだです。 僕はスタティックなスコープだけを考えてました。書き忘れました。一応僕の 考えている(かっこ悪い ^^;)局所メソッドモデルを定義しときます。 * ネストしたメソッドのスコープは定義開始から、親メソッドの定義終了行 まで。(スタティック) * ネストしたメソッドには "foo$bar", "foo$bar$hoge" というふうに、ス コープを限定するために prefix ("foo$" "foo$bar$" など) をつけて管 理する。 * メソッドの ID はコンパイル時に決定する。 * 局所メソッドは hoge(...) といった関数形式でしか呼べない ^^;;; モデルにはなってないですね…。例です。 def foo # foo def bar # foo$bar のスコープ始点 end bar # self.send("foo$bar".id) end # foo$... のスコープ終点 bar # self.send("bar".id) #これをメソッドだと言い張るのには無理があるなぁ… __;; >>> "shugo" == MAEDA Shugo writes: > 前田@大阪大学です。 > 檜田> メソッド foo$bar が未定義かどうかを静的にチェックできるかどうかが問題っ > 檜田> てとこでしょうか。静的に解決できそうな気はしますが。 > > 静的にというのがどういう意味かわからなかったのですが、コンパイル時に > 呼び出されるメソッドを決定可能であるという意味ならば無理だと思います。 > # というかそもそもRubyには静的束縛ってないですよね? あ、いえ、メソッドのID ("foo$baa".id or "baa".id) をコンパイル時に決め られるかどうか?という意味でした。 shugo> 僕がいいたかったのは、 shugo> 松本> * barが有効なのはスタティックなスコープの範囲内か,それと shugo> 松本> もfooメソッド実行中はFooクラスのインスタンスで有効なのか shugo> shugo> の後者を採用するとすれば(おそらく採用されるとすればこちらだと思います)、 shugo> barというメソッドの探索時にfoo(場合によっては他の複数のメソッド)が実行中 shugo> かどうかのチェックなどが入るので、そのコストはどれくらいなんだろうという shugo> ことです。 後者についての話でしたか…。たしかに大変そうですね。 shugo> そういえば、このモデルだと、 shugo> shugo> def foo shugo> def bar shugo> puts "foo$bar" shugo> end shugo> baz shugo> end shugo> shugo> def bar shugo> puts "bar" shugo> end shugo> shugo> def baz shugo> bar shugo> end shugo> shugo> でbazを呼び出したらどうなるんでしょう。 僕の定義なら ==> "bar" ですね。後者なら ==> "foo$bar" かな…。局所では なく一時か。(後者が ==> "bar" だとしたら両者に差異はなさそうだし) 僕はもともと他への影響をなくすために、局所的なメソッド(っていうか関数 ^^;)が欲しかったので、前者を意図してました。 でも関数だし…。採用はむりかな… ^^;。折角なので、自分で作ってみました 。特異メソッドについては考えるのを放棄したので対応してません。おもちゃ ですけど、パッチつけときます。(手抜きです ary_ とかつかってます ^^;) --- parse.y.orig Fri Nov 27 19:42:59 1998 +++ parse.y Sat Nov 28 00:12:02 1998 @@ -110,4 +110,15 @@ static NODE *cur_cref; +static void lmethod_init(); +static ID lmethod_curid(ID); +static ID lmethod_push(ID); +static ID lmethod_pop(); +static ID lmethod_defined_p(ID); +static ID LM_METHODID(id){ /* ^^; */ + ID lid; + lid = lmethod_defined_p(id); + return lid ? lid : id; +} + static void top_local_init(); static void top_local_setup(); @@ -243,4 +254,5 @@ if ((VALUE)the_class == cObject) class_nest = 0; else class_nest = 1; + lmethod_init(); } compstmt @@ -411,5 +423,5 @@ command_call : operation call_args { - $$ = new_fcall($1, $2); + $$ = new_fcall(LM_METHODID($1), $2); fixpos($$, $2); } @@ -1010,5 +1022,5 @@ | operation iter_block { - $2->nd_iter = NEW_FCALL($1, 0); + $2->nd_iter = NEW_FCALL(LM_METHODID($1), 0); $$ = $2; } @@ -1144,7 +1156,7 @@ | kDEF fname { - if (cur_mid || in_single) + if (in_single) yyerror("nested method definition"); - cur_mid = $2; + cur_mid = lmethod_push($2); local_push(); } @@ -1154,8 +1166,8 @@ { /* NOEX_PRIVATE for toplevel */ - $$ = NEW_DEFN($2, $4, $5, class_nest?0:1); - fixpos($$, $4); - local_pop(); - cur_mid = 0; + cur_mid = lmethod_pop(); + $$=NEW_DEFN(lmethod_curid($2), $4, $5, class_nest?0:1); + fixpos($$, $4); + local_pop(); } | kDEF singleton '.' {lex_state = EXPR_FNAME;} fname @@ -1281,5 +1293,5 @@ method_call : operation '(' opt_call_args ')' { - $$ = new_fcall($1, $3); + $$ = new_fcall(LM_METHODID($1), $3); fixpos($$, $3); } @@ -3451,4 +3463,7 @@ return NEW_LIT(INT2FIX(sourceline)); } + else if (lmethod_defined_p(id)) { + return NEW_VCALL(lmethod_curid(id)); + } else if (is_local_id(id)) { if (dyna_in_block() && dyna_var_defined(id)) return NEW_DVAR(id); @@ -3950,4 +3965,81 @@ { cur_cref = cur_cref->nd_next; +} + +static VALUE lmethod_stack = 0; +static VALUE lmethod_defined = 0; + +static void +lmethod_init() +{ + if (!lmethod_stack) { + lmethod_stack = ary_new(); + lmethod_defined = ary_new(); + } +} + +static VALUE +lmethod_curname_i(mid, tmp) + VALUE mid, tmp; +{ + char *name; + name = rb_id2name(NUM2INT(mid)); + str_cat(tmp, name, strlen(name)); + str_cat(tmp, "$", 1); + return Qnil; +} + +static VALUE +lmethod_curname() +{ + VALUE name; + name = str_new2(""); + rb_iterate(rb_each, lmethod_stack, lmethod_curname_i, name); + return name; +} + +static ID +lmethod_curid(ID mid) +{ + VALUE vname; + char *name; + vname = lmethod_curname(); + name = rb_id2name(mid); + str_cat(vname, name, strlen(name)); + return rb_intern(RSTRING(vname)->ptr); +} + +static ID +lmethod_push(ID mid) +{ + ID id; + id = lmethod_curid(mid); + /*fprintf(stderr, "%s pushed\n", rb_id2name(id));*/ + ary_push(lmethod_stack, INT2NUM(mid)); + ary_push(lmethod_defined, INT2NUM(id)); + return id; +} + +static ID +lmethod_pop() +{ + ary_pop(lmethod_stack); + if (RARRAY(lmethod_stack)->len) { + return NUM2INT(RARRAY(lmethod_stack)->ptr[0]); + }else { + lmethod_defined = ary_new(); + return 0; + } +} + +static ID +lmethod_defined_p(ID mid) +{ + ID lid; + lid = lmethod_curid(mid); + if (ary_includes(lmethod_defined, INT2NUM(lid))) + return lid; + else + return 0; } -- 檜田 和浩 ( hiwada@kuee.kyoto-u.ac.jp )