Ответ 1
Основной модуль 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
важно помнить, что то, что он возвращает, является декомпилированной версией скомпилированного дерева op-кодов, а не исходного исходного текста. Это означает, что константы, арифметические выражения и другие конструкции могут быть свернуты и переписаны оптимизатором.
Другая часть головоломки имеет дело с закрытыми над лексическими переменными. Если подпрограммы, с которыми вы работаете с доступом к любым внешним лексическим файлам, они не будут присутствовать в выводе deparse и не приведут к перекомпиляции. Вы можете решить это с помощью функций closed_over
и set_closed_over
из модуля PadWalker.
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";
который печатает что-то вроде:
CODE(0x28dcffc) at filename.pl line 21