データ構造・構文木のノード
Rubyプログラムはいったん構文木に変換されます。YARVのコアではRubyプログラムを文字列として扱うのではなく、常にこの構文木になった状態を使います。構文木は、以下のような構造体で表現されます。
typedef struct RNode { unsigned long flags; char *nd_file; union { struct RNode *node; ID id; VALUE value; VALUE (*cfunc)(ANYARGS); ID *tbl; } u1; union { struct RNode *node; ID id; long argc; VALUE value; } u2; union { struct RNode *node; ID id; long state; struct global_entry *entry; long cnt; VALUE value; } u3; } NODE;
えーとなんだか長いですが。ありがたいことに、RHG 第12章 に完全な解説があります。
- flags に、ノードの種類(NODE_METHOD, NODE_IF, NODE_STR, 等々) が入っている
- nd_type(node) というマクロで、ノードの種類をとりだせる
- switch(nd_type(node)) で処理を切り分けるのが定型パターン
- ノードの種類に応じて、最大3個の子ノードがある。u1, u2, u3 に入っている
- 例えばifなら条件式、then式、else式の3つ
- "u1"のような素っ気ない名前の代わりに、nd_cond や nd_else などのマクロが用意されてて、普通はそれでnode.nd_else のようにアクセスする
- 要は、node.nd_*** と来たら何か子ノードへのアクセス
これだけ覚えておけばあとはだいたい読めそうです。