Ruby スクリプトの内部表現をチラ見する（書きかけ）

# 前説
## この記事は
Ruby スクリプトが CRuby(MRI) でどう変換されてどう実行されるのか、興味があって見てみたいと思って調べた結果についての記事、になるはずだったものです。
書きかけで投げ出してしまっているので、そういうのが嫌な人にはおすすめしません。

## 要するに
--dump に感動したのでみんな使おうぜ、あと使っててわかったことがあったら共有しようぜ、という、それだけです。あと、わかりにくい出力が一部あったので、そこについて説明しています。

# CRuby のオプション --dump=XXX
## とは
CRuby には、--dump=XXX というとても素敵なオプションを渡すことができます。
これを指定すると、Ruby スクリプトは実行されず、そのコードが ruby の内部でどのような形で表現されるのかを知ることができます。

## XXX に入るもの
XXX の部分は本当に XXX と書くわけではなく、以下の 2 つのいずれかを渡すことができます。

* insns
    * ruby の VM (YARV とか呼ばれている（いた？）あいつです) の命令列を見ることができます
*  parsetree
    * 上の VM 命令列にコンパイルされるより前の段階の、「ノード」と言われる中間表現をみることができます

# 動作例
## スクリプトの用意
動作を確認するために、スクリプトを用意します。
とりあえず簡単に、`a,b = nil` でいってみたいと思います。
（なぜ `a = nil` でないかというと、多重代入の動きが見たかったからです）

## まずはプレーン
最初に、--dump なしで動かしてみました。

```
$ ruby -e 'a, b = nil'
$
```

`p` も `puts` もしていないので何も出力されずに少し寂しいですが、想定通りです。

## insns

次に、VM の命令列 insns です。

```
$ ruby --dump=insns -e 'a, b = nil'
== disasm: <RubyVM::InstructionSequence:<main>@-e>======================
local table (size: 3, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 3] a          [ 2] b          
0000 trace            1                                               (   1)
0002 putnil           
0003 dup              
0004 expandarray      2, 0
0007 setlocal_OP__WC__0 3
0009 setlocal_OP__WC__0 2
0011 leave            
$
```

なんだかいっぱい出ています。

`a` と `b` の 2 つのローカル変数が定義されていて、内部的には a を 3 番、b を 2 番と呼んでる、っぽいような、そんなことが 3 行目から読み取れる、ような気がします。

へー、タイプ 1 で `trace` するんだー、スタックに `nil` をおいて `dup` してから `expandarray` したものでそれぞれ `setlocal` するんだー 3 番（ローカル変数 a）と 2 番（ローカル変数 b）にねー、ふーん、などと読んでいきます。

何言っているかわからないと思います。書いてる本人もわかりません。

### 補足
とりあえずここでは大まかなイメージだけわかればいいと思います。
これより深いところは VM の動作の領域であって今回の「内部表現をチラ見する」という趣旨とは外れるので割愛します。

### 本当は
わかってないので説明できないだけです。すみません。
詳しい人の詳しい話を見たり聞いたりしてください。

## parsetree
次に、ノード表現 parsetree です。

```
$ ruby --dump=parsetree -e 'a, b = nil'
###########################################################
## Do NOT use this node dump for any purpose other than  ##
## debug and research.  Compatibility is not guaranteed. ##
###########################################################

# @ NODE_SCOPE (line: 1)
# +- nd_tbl: :a,:b
# +- nd_args:
# |   (null node)
# +- nd_body:
#     @ NODE_MASGN (line: 1)
#     +- nd_value:
#     |   @ NODE_NIL (line: 1)
#     +- nd_head:
#     |   @ NODE_ARRAY (line: 1)
#     |   +- nd_alen: 2
#     |   +- nd_head:
#     |   |   @ NODE_DASGN_CURR (line: 1)
#     |   |   +- nd_vid: :a
#     |   |   +- nd_value:
#     |   |       (null node)
#     |   +- nd_next:
#     |       @ NODE_ARRAY (line: 1)
#     |       +- nd_alen: 140562125983720
#     |       +- nd_head:
#     |       |   @ NODE_DASGN_CURR (line: 1)
#     |       |   +- nd_vid: :b
#     |       |   +- nd_value:
#     |       |       (null node)
#     |       +- nd_next:
#     |           (null node)
#     +- nd_args:
#         (null node)
$
```

はじめに注意書きが出力されます。互換性とか保証されないからデバッグと調査にしか使うなよーとのこと。

やはり最初に、`a` と `b` の 2 つのローカル変数があるということを言っている、ような気がします。

ははあ MASGN というのは multi assign、多重代入のことかな、nd_value には 右辺が、nd_head には左辺が入っているっぽいな、などと読んでいきます。

### 不審な数字
下の方の行に、nd_alen: 140562125983720 という、なんだかよくわからないものが出力されています。なんでしょうか。

# といったところで

実はこの値は nd_alen じゃなくて nd_end なんだよー同じ NODE_ARRAY でも u2 の使い方が二通りあるんだよーという話を、どう書くのがいいかわからなくなってきました。ぶっちゃけ面倒になってきて投げ出しました。

ただ、別にバグではないんだよということと、--dump が便利だということは言いたかったので、もうこの状態で公開してしまいます。

詳しく知りたい人はソース読んだり詳しい人に聞いてみてください。
詳しい人はどこかで解説してくれたりすると嬉しいです。