NODE_OP_ASGN_OR 等
続いて、属性や添字式以外への、要するに普通の変数への &&= か ||= のノードです。繰り返しになりますが、普通の変数への += 等は = と + の組み合わせに展開して問題ないので、特別には扱われていません。というわけで、これが自己代入系最後のノードです。
この場合も生成されるコードは、ほぼここまでで説明したとおりで、そんなに特殊なことはやってません。でも ||= のバイトコードで一カ所ちょっと気になりました。&&= の方は特にひっかからなかったのでこれまた省略しちゃいます。
#x ||= v eval defined?(x) # branchunless lassign # ← ? eval x dup branchif lfin pop lassign: eval x=v lfin:
左辺の変数がdefinedかどうかチェックして、そうでなければevalを飛ばしていきなり右辺値の代入までジャンプしています。該当部のコードはこちら。
if (nd_type(node) == NODE_OP_ASGN_OR) {
defined_expr(iseq, ret, node->nd_head, lassign, Qfalse);
ADD_INSNL(ret, nd_line(node), branchunless, lassign);
}
defined_expr の詳細はあとで NODE_DEFINED の時に読むとして、要するに、Ruby の defined? に当たる命令列を生成してくれる関数です。
この分岐は、「まだ定義されてなかったら、そのときだけ、変数/定数に値を入れる」という目的で使われる ||= をサポートするため、かな?
Constant ||= 123 print Constant
こんなの。yarv で実行すると 123 が表示されます。これを上記の4行をコメントアウトしてビルドしたyarvで動かすと
C:\Desktop> yarv -v test.rb ruby 1.9.0 (Base: Ruby 1.9.0 2006-11-06) [i386-mswin32] YARVCore 0.4.1 Rev: 581 (2006-11-10) [opts: [inline method cache] ] test.rb:1:in `<main>': uninitialized constant Constant (NameError)
怒られました。ただ現行のRubyでも
C:\Desktop> ruby -v test.rb ruby 1.9.0 (2006-04-15) [i386-mswin32] test.rb:1: uninitialized constant Constant (NameError)
どうなんだろう。保留。