Devel-Chitin
view release on metacpan or search on metacpan
lib/Devel/Chitin/OpTree.pm view on Meta::CPAN
package Devel::Chitin::OpTree;
use strict;
use warnings;
our $VERSION = '0.22';
use Carp;
use Scalar::Util qw(blessed reftype weaken refaddr);
use B qw(ppname);
use Devel::Chitin::OpTree::UNOP;
use Devel::Chitin::OpTree::SVOP;
use Devel::Chitin::OpTree::PADOP;
use Devel::Chitin::OpTree::COP;
use Devel::Chitin::OpTree::PVOP;
use Devel::Chitin::OpTree::METHOP;
use Devel::Chitin::OpTree::BINOP;
use Devel::Chitin::OpTree::LOGOP;
use Devel::Chitin::OpTree::LOGOP_AUX;
use Devel::Chitin::OpTree::LISTOP;
use Devel::Chitin::OpTree::LOOP;
use Devel::Chitin::OpTree::PMOP;
BEGIN {
if ($^V ge v5.22.0) {
require Devel::Chitin::OpTree::UNOP_AUX;
}
}
my %objs_for_op;
sub _obj_for_op {
my($self, $op) = @_;
$objs_for_op{$$op};
}
sub build_from_location {
my($class, $start) = @_;
my($start_op, $cv) = _determine_start_of($start);
# adapted from B::walkoptree_slow
my @parents;
my $build_walker;
$build_walker = sub {
my $op = shift;
my $self = $class->new(op => $op, cv => $cv);
$objs_for_op{$$op} = $self;
weaken $objs_for_op{$$op};
my @children;
if ($$op && ($op->flags & B::OPf_KIDS)) {
unshift(@parents, $self);
for (my $kid_op = $op->first; $$kid_op; $kid_op = $kid_op->sibling) {
push @children, $build_walker->($kid_op);
}
shift(@parents);
}
if (B::class($op) eq 'PMOP'
and ref($op->pmreplroot)
and ${$op->pmreplroot}
and $op->pmreplroot->isa('B::OP')
) {
unshift @parents, $self;
push @children, $build_walker->($op->pmreplroot);
shift @parents;
}
@$self{'parent','children'} = ($parents[0], \@children);
$self;
};
$build_walker->($start_op);
}
sub _determine_start_of {
my $start = shift;
if (reftype($start) eq 'CODE') {
my $cv = B::svref_2object($start);
return ($cv->ROOT, $cv);
}
unless (blessed($start) and $start->isa('Devel::Chitin::Location')) {
Carp::croak('build_from_location() requires a coderef or Devel::Chitin::Location as an argument');
}
if ($start->package eq 'main' and $start->subroutine eq 'MAIN') {
return (B::main_root(), B::main_cv);
} elsif (my $subref = $start->subref) {
my $cv = B::svref_2object($subref);
return ($cv->ROOT, $cv);
} elsif ($start->subroutine =~ m/::__ANON__\[\S+:\d+\]/) {
Carp::croak(q(Don't know how to handle arbitrary anonymous subs yet));
} else {
my $subname = join('::', $start->package, $start->subroutine);
my $subref = do { no strict 'refs'; \&$subname };
my $cv = B::svref_2object($subref);
return ($cv->ROOT, $cv);
}
}
sub new {
my($class, %params) = @_;
unless (exists $params{op}) {
( run in 1.924 second using v1.01-cache-2.11-cpan-b16cb0d3907 )