我目前正在一个非常复杂的Perl架构,我想创建一些调试工具.由于很多行为涉及匿名子程序,我想分析一些行为,所有我需要处理的是对子程序的引用.
解决方法
核心模块
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
use B (); my $Meta = B::svref_2object($closure); print "$closure at ".$Meta->FILE.' line '.$Meta->GV->LINE."\n";
其打印如下:
CODE(0x28dcffc) at filename.pl line 21