Ruby構文木のオブジェクト化

普段はソースの奥底に隠れている構文木を、RubyオブジェクトとしてRubyの世界にひっぱりだすコードを書いてみた。こんな感じにつかえる。108つもあるRuby構文木ノードのうち、まだ半分くらいしか解析できてないけど。

irb(main):001:0> require 'rbnode'
=> true
irb(main):002:0> def fact(n)
irb(main):003:1>  if n == 1 then 1 else n * (fact(n-1)) end
irb(main):004:1> end
=> nil
irb(main):005:0> n = RBNode.make(self,:fact)
=> #<RBNode::NODE_METHOD:0x40580efc @body=#<RBNode::NODE_SCOPE:0x40580e5c @next=#<RBNode::NODE_BLOCK:0x40580ca4 @block_body=[#<RBNode::NODE_ARGS:0x40580d1c @opt=nil, @cnt=1, @rest=-1>, #<RBNode::NODE_IF:0x40580b64 @cond=#<RBNode::NODE_CALL:0x40580ac4 @mid=:==, @args=#<RBNode::NODE_ARRAY:0x405809ac @block_body=[#<RBNode::NODE_LIT:0x4058090c @lit=1>], @alen=1>, @recv=#<RBNode::NODE_LVAR:0x40580a24 @cnt=2, @vid=:n>>, @else=#<RBNode::NODE_CALL:0x40580754 @mid=:*, @args=#<RBNode::NODE_ARRAY:0x4058063c @block_body=[#<RBNode::NODE_FCALL:0x405804fc @mid=:fact, @args=#<RBNode::NODE_ARRAY:0x4058045c @block_body=[#<RBNode::NODE_CALL:0x405803bc @mid=:-, @args=#<RBNode::NODE_ARRAY:0x405802a4 @block_body=[#<RBNode::NODE_LIT:0x40580204 @lit=1>], @alen=1>, @recv=#<RBNode::NODE_LVAR:0x4058031c @cnt=2, @vid=:n>>], @alen=1>>], @alen=1>, @recv=#<RBNode::NODE_LVAR:0x405806b4 @cnt=2, @vid=:n>>, @then=#<RBNode::NODE_LIT:0x40580844 @lit=1>>]>>, @noex=0>
irb(main):006:0> pp n
<METHOD
 @body=<SCOPE
   <BLOCK
    [<ARGS @opt=nil @cnt=1 @rest=-1>,
     <IF
      @cond=<CALL
        @mid=:==
        @args=<ARRAY [<LIT @lit=1>]>
        @recv=<LVAR @cnt=2 @vid=:n>>
      @else=<CALL
        @mid=:*
        @args=<ARRAY
          [<FCALL
            @mid=:fact
            @args=<ARRAY
              [<CALL
                @mid=:-
                @args=<ARRAY [<LIT @lit=1>]>
                @recv=<LVAR @cnt=2 @vid=:n>>]>>]>
        @recv=<LVAR @cnt=2 @vid=:n>>
      @then=<LIT @lit=1>>]>>
 @noex=0>
=> nil

木構造がわかりやすくなるようにNEWLINEとか消して、表示もシンプルにしてあるので注意。

[2007-03-11]追記

はてブid:sumimさんに

Coke d:id:sumim:20070307:p1 によるなんちゃって Ruby の実装に使えるかも…

というコメントを頂きましたが、Ruby構文木を表示するだけなら、Typing Ruby(http://truby.sourceforge.jp/index.j.html)やRHG(http://i.loveruby.net/ja/rhg/)の中で使われているnodedumpが便利ですよ。CokeでRubyが動くと格好いいなあ。