打印出匿名子程序的代码 [英] Printing out the code of an anonymous subroutine

查看:47
本文介绍了打印出匿名子程序的代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前在一个非常复杂的 Perl 架构中工作,我想创建一些调试工具.由于很多行为涉及匿名子例程,我想分析一些行为,我所要做的就是对子例程的引用.

简而言之,有没有办法打印子程序引用的代码(因为 Perl 被解释它可能仍然可用?)?

解决方案

核心模块 B::Deparse 提供了这个功能.

使用B::Deparse();我的 $deparse = B::Deparse->new;我的 $code = sub {print "hello, world!"};打印 'sub', $deparse->coderef2text($code), "\n";

打印:

sub {打印你好,世界!";}

在使用 B::Deparse 时,重要的是要记住它返回的是已编译操作码树的反编译版本,而不是原始源文本.这意味着常量、算术表达式和其他结构可能会被优化器折叠和重写.

谜题的另一部分是处理封闭的词法变量.如果您使用的子程序访问任何外部词法,它们将不会出现在 deparse 的输出中,并且会导致重新编译失败.您可以使用 closed_over 和 set_closed_over 函数解决此问题>PadWalker 模块.

使用PadWalker qw/closed_over set_closed_over/;我的 $closure = 做 {我的 $counter = 0;子{$counter++}};打印 $closure->(), ' ' for 1..3;# 0 1 2打印\n";我的 $pad = closed_over $closure;# 词法哈希# 为编译创建虚拟词法my $copy = eval 'my ('.join(','=> keys %$pad).');'.'sub'.$deparse->coderef2text($closure);set_closed_over $copy, $pad;# 用真实词法替换虚拟词法打印 $copy->(), ' ' for 1..3;# 3 4 5

最后,如果你想找出子程序真正的源代码在哪里,可以使用核心B 模块:

使用B();我的 $meta = B::svref_2object($closure);打印 "$closure at ".$meta->FILE.'行 '.$meta->GV->LINE."\n";

打印如下内容:

<前>CODE(0x28dcffc) 在 filename.pl 第 21 行

I'm currently working in a very complex Perl architecture, and I want to create some debugging tools. Since a lot of the behavior involves anonymous subroutines, I'd like to analyze some of the behavior, and all I have to work with is a reference to the subroutine.

In short, is there a way to print the code (since Perl is interpreted it may still be available?) of a subroutine reference?

解决方案

The core module B::Deparse provides this functionality.

use B::Deparse ();

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

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

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

which prints:

sub {
    print 'hello, world!';
}

When using B::Deparse it is important to remember that what it returns is a decompiled version of the compiled tree of op-codes, not the original source text. This means that constants, arithmetic expressions, and other constructs may be folded and rewritten by the optimizer.

The other part of the puzzle is dealing with closed over lexical variables. If the subroutines you are working with access any external lexicals, they will not be present in the output of deparse, and will cause recompilation to fail. You can solve this with the closed_over and set_closed_over functions from the PadWalker module.

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

Finally, if you want to find out where the subroutine's real source code is, you can use the core B module:

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

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

which prints something like:

CODE(0x28dcffc) at filename.pl line 21

这篇关于打印出匿名子程序的代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆