Acme::Don`t 2.0

Acme::Don't 2.0
Bモジュールで覗くPerlの深淵
Goro Fuji
gfx at Hatena
GFUJI at CPAN
http://d.hatena.ne.jp/gfx/20080929/1222669383より
use Acme::Don't 2.0;
#!perl -w
use Acme::Don't 2.0;
use feature 'say';
don't {
say "don't";
don't {
say "done!";
};
say "don't";
};
# => done!
use B;
B - The Perl Compiler
 Bモジュールの機能


SV構造体にアクセス
 Sub::Identify

OP構文木にアクセス
 B::Deparse
SV構造体 = Perlデータオブジェクト

Perlのデータは全てSVとして表現される
$foo
#SV
#
#
#
#};
= 10;
= {
refcount => 1,
flags
=> IOK, # Integer OK
int_value => 10,
SV構造体のプロパティ

スカラー
IV(整数)
 PV(文字列)


などなど
$foo = Scalar::Util::dualvar(42, "foo")
#SV = {
#
refcount => 1,
#
flags
=> (IOK | POK),
#
int_value => 42,
#
ptr_value => "foo",
#};
CV = Code ValueもSVの一種
コードリファレンスが参照しているもの
 Perlレベルからはアクセスできない



参照できるプロパティはそのアドレスだけ
しかし,有用なプロパティも沢山ある

CvGV - 型グロブ(たとえば*main::f)
 そこでBモジュールですよ!
Bモジュールの使用例

Sub::Identify
package Sub::Identify;
# 単純化してあるものの,大体こんな感じ
# GV->STASH は GVの所属するSymbol Table Hash
#
(*glob{PACKAGE}のようなもの)
# GV->NAME は *glob{NAME}と同じ
sub get_code_info{
my $code_ref = shift;
my $cv = B::svref_2object(\&{$code_ref});
my $gv = $cv->GV;
return ($gv->STASH->NAME, $gv->NAME);
}
OP構文木 = OP構造体のツリー
Perlの構文木にアクセスする機能を提供する
 B - Perl Compiler Backend
 B::*モジュール群が代表的

B::Deparse
 B::Concise
 B::Lint


Acme::Don't 2.0もこの機能を使っている
Acme::Don't 2.0のメカニズム

don't{ ... } = &don::t(sub{ ... })
この呼び出しに相当する構文木を単純化すると:
entersub (上の娘たちを引数に末娘を呼び出す)
├refgen (娘SVのリファレンスを生成)
│ └anoncode (無名サブルーチンの実体を参照)
└gv[*don::t] (*dont::tを参照)
(実行順:anoncode -> refgen -> gv -> entersub)
そこで,まずrefgenを探し,妹がgv[*don::t]だったら
refgenの娘のanoncodeを実行する
まとめ

Bモジュールは二つの機能がある
SV構造体へのアクセス
 OP構文木へのアクセス


構文木へアクセスすると

サブルーチンを実行せずに中身を調べられる
 特定のシンボルを探したり
 特定の制御構造を探したり
 サブルーチンの「大きさ」を調べたり

cf. PPI
ご清聴ありがとうございました

お招きいただいたTAKESAKOさんに感謝し
ます。

Acme::Don'tを書くきっかけになったもの

Shibuya.pm #9
 tokuhirom氏のLT
(autobox, Perl VM Golf)
 stanaka氏のLT (GDB for Perl)