ひとり勉強会

ひとり楽しく勉強会

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)

どうなんだろう。保留。