assert { ... }
と書けば、ブロックの評価値に応じてアサーションします。キーワードプラグインを利用することで本番環境などアサーションが不要な時にパフォーマンスを損ねることなく利用できることが特徴です。コンパイル型言語のアサーションと同様の使い勝手だと思います。
use Syntax::Keyword::Assert; sub hello($name) { assert { defined $name }; say "Hello, $name!"; } hello("Alice"); # => Hello, Alice! hello(); # => Dies when STRICT mode is enabled
キーワードプラグインとは?
キーワードプラグインとは、Perlのパーサーにフックして構文拡張する機能で、Perlの開発者のPaul Evans氏がフル活用しています。 氏は、Perl本体に手をいれることなく、キーワードプラグインを利用して試作品をまず作り、コミュニティからのフィードバックを経て、Perl本体に取り込む進め方をしています。最近の try/catch, defer, class といった文法拡張はその結実です。
- キーワードプラグインを利用したモジュールの例
- Syntax::Keyword::Try - a try/catch/finally syntax for perl - metacpan.org
- Syntax::Keyword::Defer - execute code when leaving a block - metacpan.org
- Syntax::Operator::Equ - equality operators that distinguish undef - metacpan.org
- Syntax::Operator::Is - match operator using Data::Checks constraints - metacpan.org
- Object::Pad - a simple syntax for lexical field-based objects - metacpan.org
キーワードプラグインの動作のイメージは、こんな感じです。
- ① パーザーが指定キーワードを発見!今回ならassert
- ② 指定キーワード周辺のOPツリー(抽象構文木のようなもの)に、好みのOPツリーを差し込む!以上です!
例えば、このSyntax::Keyword::Assertの場合、assert { defined $name }
は、次のコードと等価になるようにOPツリーを組み立てています。
# STRICTが有効な場合 croak 'Assertion failed' unless do { defined $name } # STRICTが無効な場合は何もしない。
より具体的なソースコードはこちら
面白いですね!
開発話
余談ですが、OPツリーの組み立ては慣れてなかったので、その段取りを備忘として書き留めます。
まず、こんなサイクルで進めました。
- 最初にキーワードで置き換えたい内容を Pure Perl で書く
- 今回なら
croak ... unless BLOCK
- 今回なら
- このコードに、B::Concise, B::Terse, B::Debug などを通して、OPツリーを把握する
- 試しに書いたOPツリーが、👆のOPツリーと一致するか確かめる
- 加えて、B::Deparseをして、期待するコードになっているか確かめる
- → 期待通りになるまで頑張る
また、次の資料を参考にしました。
- キーワードプラグインを利用したモジュールのソースコード
- 今回なら、
KEYWORD BLOCK
という文法なので、Syntax::Keyword::Defer とOPツリーの組み立て以外、基本同じでした。
- 今回なら、
- perlapiも読みつつ、perl本体のop.c や opnames.h も読むとOPツリーの組み立てが理解しやすかったです
- そもそも SV、OPといった用語がよくわからない場合は、tokuhiromさんのこちらの記事を読むとイメージがつかめると思います。 C による Perl 拡張入門(
- Yet Another CPAN Grep で関連コードを探すことも何度もしました
以上です! Happy Hacking!