goccyでごっしー

技術的な話題をつらつらと書いたり書かなかったり

最近のCompiler::Parserについて

最近、Compiler::Parserの0.0.9をリリースしましたが、0.0.8から大分変更がありました。

大きく分けて2つあり、find/remove/walkメソッドのサポートと、大量のバグフィックスです

 

find/remove/walkメソッドのサポート

findに関してはCompiler::Parser::ASTやCompiler::Parser::Nodeを継承するすべてのモジュールに実装されており、remove/walkメソッドはCompiler::Parser::ASTに実装されています。

よくあるuse/requireしているモジュールの名前とexportされている関数の一覧を取得するようなコードは、findを使うと以下の様な感じに書けます

 

findの引数になっている'node'というkeyに対応して、Compiler::Parser::Nodeを継承しているモジュールの名前を指定すると、そのノードのリストを取得することができます。

同様に、find(type => 'Int')とすると、Compiler::Lexer::TokenのtypeがInt(Compiler::Lexer::Type::T_Int)であるtokenを持つノードのリストを取得します。

他にも、'kind'や'data'といったkeyを指定してノードを取得することもできます。

指定する名前のルールがわからないよ!という場合は、Compiler::Parser::Nodeの実装を見れば、サクッと分かっていただける気がしています。

(後日ちゃんとドキュメント化しようと思います)

 

removeは、対象となったノードをASTから削除することができます。

walkメソッドは、

* walk { my $node = $_ } $ast 

* $ast->walk(sub { my $node = shift; });

のような形式で使うことができ、AST上のノードを端から端まで探索したいときなどに使えます。

 

大量のバグフィックス

現在、Compiler::Parserのparse精度を高めるために、程よく大きく、多彩なシンタックスを使っていて、広く使われているものとして、Plackを対象に動作検証を行っています。

2014年4月現在で、Plack/Middleware以下のモジュールを除いた全てのモジュールのparseがうまくいくことを確認しており、以前よりも大分完成度が上がってきた気がしています。

(Middleware以下は、単にモジュールの数が多くて後回しになっています...)

parse結果はテストコードとして自動生成していて、テストコードを生成するタイミングで目視で整合性を確認しています。(うまくいっているかどうかの判断基準は難しいのですが、現状だと、ASTから正しいbytecodeが生成できるかどうかで判断しています)

目視確認せずに正確性を検証したいところではありますが、現状こんな感じでやっています。

 

テストコードがどうなっているかは、この辺から確認できます。

テストコードを見れば、生成されているASTのレイアウトがどんな感じなのかざっくりと分かっていただけるようになっています。

 

今後

Plack配下のモジュールを全てparseできた段階で0.1.0をリリースしようと思っています。また、併せてASTからソースコードを逆生成するdeparseメソッドを追加しようと考えています。このメソッドがあることによって、ASTが正しいかどうかが誰でも検証できるようになると思っています。(sourceA -> parse -> AST -> deparse -> sourceBでsourceAとsourceBが同じであれば、parse結果が概ね正しいと言える)

  

Compiler::Parserは、ロードマップや使い方に関して、もっとドキュメントを残していく必要性を感じているので、これから暇を見つけて投稿していこうと思います。