es**シリーズの仕様意訳第二回。前回はesprimaでした。今回はestraverse。
estraverse
estraverseはASTの巡回コードをお手軽に書けるようにするモジュール。 ASTは子ノードのプロパティ名がまちまちなので、巡回させるコードを書くのが結構手間なんで重宝する。
基本的にesprimaの吐いたASTをestraverse.traverseに喰わせるだけでOK。 ここらへんも本当によくできていて、esprimaとestraverseは疎結合を保っている(AST仕様のみで結びついているといってもよい)。
ではいってみよう。estraverseと、ASTを吐かせるためのesprimaをnpmからとってくる。
npm install esprima npm install estraverse
以下のようにコードを作成。
var esprima = require('esprima');
var estraverse = require('estraverse');
var code = 'console.log("Hello, World!");';
var ast = esprima.parse(code);
estraverse.traverse(ast, {
enter: function(currentNode, parentNode) {
console.log(currentNode.type, parentNode && parentNode.type);
// this.skip(); // スキップする。
// this.break(); // 巡回を終わらせる。
},
leave: unction(currentNode, parentNode) {
console.log(currentNode.type, parentNode && parentNode.type);
// this.skip(); // スキップする。
// this.break(); // 巡回を終わらせる。
}
});
おわり。
/**
* ASTを深さ優先探索で巡回する。
* @param {AstNode} root ASTのルートノード。
* @param {EstraverseVisitor} visitor 巡回オブジェクト(Visitorパターン)。
*/
estraverse.traverse;
/**
* estraverse.traverseの第二引数。
*/
EstraverseVisitor = {
/**
* ノードに訪れたときに実行される。thisにestraverse.Controllerのインスタンスにアクセスできる。
* @param {AstNode} currentNode 訪問したノード。
* @param {AstNode} parentNode 訪問したノードの親ノード。
* @this {estraverse.Controller}
*/
enter: function(currentNode, parentNode) {},
/**
* ノードから去るときに実行される。thisにestraverse.Controllerのインスタンスにアクセスできる。
* @param {AstNode} currentNode 去るノード。
* @param {AstNode} parentNode 去るノードの親ノード。
* @this {estraverse.Controller}
*/
leave: function(currentNode, parentNode) {},
};
巡回の制御については、EstraverseVisitor.enter EstraverseVisitor.leave の this に割り当てられた estraverse.Controll インスタンスを通じておこなうか、戻り値に estraverse.VisitorOption.BREAK 、 estraverse.VisitorOption.SKIP を指定することでおこなえる。また、訪問先のAstNodeの祖先ノード達は、 estraverse.Controll#parents の実行(要するにthis.parents();)で取得できる。
おわり。