15

私は現在、非常に複雑なPerlアーキテクチャで作業しており、いくつかのデバッグツールを作成したいと考えています。多くの動作には匿名のサブルーチンが含まれるため、動作の一部を分析したいと思います。操作する必要があるのは、サブルーチンへの参照だけです。

要するに、サブルーチン参照のコードを印刷する方法はありますか(Perlは解釈されるので、まだ利用できる可能性がありますか?)?

4

4 に答える 4

27

コアモジュールB::Deparseはこの機能を提供します。

use B::Deparse ();

my $deparse = B::Deparse->new;

my $code = sub {print "hello, world!"};

print 'sub ', $deparse->coderef2text($code), "\n";

印刷するもの:

sub {
    print 'hello, world!';
}

使用するときB::Deparseは、元のソーステキストではなく、コンパイルされたオペコードツリーの逆コンパイルされたバージョンが返されることを覚えておくことが重要です。これは、定数、算術式、およびその他の構成がオプティマイザーによって折りたたまれ、書き直される可能性があることを意味します。

パズルの他の部分は、閉じた字句変数を扱うことです。使用しているサブルーチンが外部レキシカルにアクセスする場合、それらはdeparseの出力に存在せず、再コンパイルが失敗します。これは、 PadWalkerモジュールのclosed_overおよびset_closed_over関数を使用して解決できます。

use PadWalker qw/closed_over set_closed_over/;

my $closure = do {
    my $counter = 0;
    sub {$counter++}
};

print $closure->(), ' ' for 1..3; # 0 1 2
print "\n";

my $pad = closed_over $closure; # hash of lexicals

                 # create dummy lexicals for compilation
my $copy = eval 'my ('.join(','=> keys %$pad).');'. 
                'sub '.$deparse->coderef2text($closure);

set_closed_over $copy, $pad;  # replace dummy lexicals with real ones

print $copy->(), ' ' for 1..3; # 3 4 5

最後に、サブルーチンの実際のソースコードがどこにあるかを知りたい場合は、コアBモジュールを使用できます。

use B ();
my $meta = B::svref_2object($closure);

print "$closure at ".$meta->FILE.' line '.$meta->GV->LINE."\n";

これは次のようなものを印刷します:

filename.plの21行目のCODE(0x28dcffc)
于 2011-04-08T02:40:08.943 に答える
15

ええ、次のようなものを介して、Data::Dumper持ち込むように言うことができます:B::Deparse

#!/usr/bin/perl

use Data::Dumper;
use strict;
use warnings;
$Data::Dumper::Deparse = 1;

my $code = sub { my $a = 42;  print $a ** 2; };

print Dumper $code;

必要に応じて、オブジェクト指向のインターフェースもあります(のperldocで説明されていData::Dumperます)。

注:出力されるコードは、最初に指定したものと同じではありませんが、同じセマンティクスを持ちます。

于 2011-04-08T01:22:37.990 に答える
7

また、Devel :: Dwarnが設定Data::Dumperされるため、デフォルトで逆解析されます。それはすぐに私のお気に入りのダンパーになりました:

perl -MDevel::Dwarn -e "Dwarn { callback => sub { 1+1 } }"

与える

{
  callback => sub {
      2;
  }
}
于 2011-04-08T08:23:30.703 に答える
6

この種のことについては、私は常にPerlMonksの匿名coderefのファイル名/行番号を追跡するを参照します。Randalは、匿名サブルーチンにタグを付けて、それらを定義した場所を確認できるようにするというアイデアを思いつきました。私はそれを少し拡張しました。エリックが投稿したものと同じもののいくつかを使用していますが、もう少しあります。

于 2011-04-08T06:56:07.703 に答える