B-DeparseTree
view release on metacpan or search on metacpan
lib/B/DeparseTree/PPfns.pm view on Meta::CPAN
double_delim
dq
dq_unop
dquote
e_anoncode
e_method
elem
filetest
for_loop
func_needs_parens
givwhen
indirop
is_lexical_subs
is_list_newer
is_list_older
list_const
listop
logassignop
logop
loop_common
loopex
map_texts
mapop
matchop
maybe_local
maybe_local_str
maybe_my
maybe_parens
maybe_parens_func
maybe_parens_unop
maybe_qualify
maybe_targmy
_method
null_newer
null_older
pfixop
pp_padsv
range
repeat
rv2x
scopeop
single_delim
slice
split
stringify_newer
stringify_older
subst_newer
subst_older
unop
);
# The BEGIN {} is used here because otherwise this code isn't executed
# when you run B::Deparse on itself.
my %globalnames;
BEGIN { map($globalnames{$_}++, "SIG", "STDIN", "STDOUT", "STDERR", "INC",
"ENV", "ARGV", "ARGVOUT", "_"); }
BEGIN {
# List version-specific constants here.
# Easiest way to keep this code portable between version looks to
# be to fake up a dummy constant that will never actually be true.
foreach (qw(
CVf_LOCKED
OPpCONST_ARYBASE
OPpCONST_NOVER
OPpEVAL_BYTES
OPpITER_REVERSED
OPpOUR_INTRO
OPpPAD_STATE
OPpREVERSE_INPLACE
OPpSORT_DESCEND
OPpSORT_INPLACE
OPpTARGET_MY
OPpSUBSTR_REPL_FIRST
PMf_EVAL PMf_EXTENDED
PMf_NONDESTRUCT
PMf_SKIPWHITE
RXf_PMf_CHARSET
RXf_PMf_KEEPCOPY
RXf_SKIPWHITE
)) {
eval { import B $_ };
no strict 'refs';
*{$_} = sub () {0} unless *{$_}{CODE};
}
}
my %strict_bits = do {
local $^H;
map +($_ => strict::bits($_)), qw/refs subs vars/
};
BEGIN { for (qw[ pushmark ]) {
eval "sub OP_\U$_ () { " . opnumber($_) . "}"
}}
{
# Mask out the bits that L<warnings::register> uses
my $WARN_MASK;
BEGIN {
$WARN_MASK = $warnings::Bits{all} | $warnings::DeadBits{all};
}
sub WARN_MASK () {
return $WARN_MASK;
}
}
my(%left, %right);
sub ambient_pragmas {
my $self = shift;
my ($arybase, $hint_bits, $warning_bits, $hinthash) = (0, 0);
while (@_ > 1) {
my $name = shift();
my $val = shift();
if ($name eq 'strict') {
require strict;
lib/B/DeparseTree/PPfns.pm view on Meta::CPAN
return $self->info_from_string("$my", $op, "$my $text");
} elsif ($self->func_needs_parens($text, $cx, 16)) {
return $self->info_from_string("$my()", $op, "$my($text)");
} else {
return $self->info_from_string("$my", $op, "$my $text");
}
} else {
return $self->info_from_string("not my", $op, $need_parens ? "($text)" : $text);
}
}
sub maybe_my_older
{
my $self = shift;
my($op, $cx, $text, $forbid_parens) = @_;
if ($op->private & OPpLVAL_INTRO and not $self->{'avoid_local'}{$$op}) {
my $my_str = $op->private & OPpPAD_STATE
? $self->keyword("state")
: "my";
if ($forbid_parens || B::Deparse::want_scalar($op)) {
return $self->info_from_string('my', $op, "$my_str $text");
} else {
return $self->info_from_string('my (maybe with parens)', $op,
"$my_str $text",
{maybe_parens => [$self, $cx, 16]});
}
} else {
return $self->info_from_string('not my', $op, $text);
}
}
# Possibly add () around $text depending on precedence $prec and
# context $cx. We return a string.
sub maybe_parens($$$$)
{
my($self, $text, $cx, $prec) = @_;
if (B::DeparseTree::TreeNode::parens_test($self, $cx, $prec)) {
$text = "($text)";
# In a unop, let parent reuse our parens; see maybe_parens_unop
# FIXME:
$text = "\cS" . $text if $cx == 16;
return $text;
} else {
return $text;
}
}
# FIXME: go back to default B::Deparse routine and return a string.
sub maybe_parens_func($$$$$)
{
my($self, $func, $params, $cx, $prec) = @_;
if ($prec <= $cx or substr($params, 0, 1) eq "(" or $self->{'parens'}) {
return ($func, '(', $params, ')');
} else {
return ($func, ' ', $params);
}
}
# Sort of like maybe_parens in that we may possibly add (). However we take
# an op rather than text, and return a tree node. Also, we get around
# the 'if it looks like a function' rule.
sub maybe_parens_unop($$$$$)
{
my ($self, $name, $op, $cx, $parent, $opts) = @_;
$opts = {} unless $opts;
my $info = $self->deparse($op, 1, $parent);
my $fmt;
my @exprs = ($info);
if ($name eq "umask" && $info->{text} =~ /^\d+$/) {
# Display umask numbers in octal.
# FIXME: add as a info_node option to run a transformation function
# such as the below
$info->{text} = sprintf("%#o", $info->{text});
$exprs[0] = $info;
}
$name = $self->keyword($name);
if ($cx > 16 or $self->{'parens'}) {
my $node = $self->info_from_template(
"$name()", $parent, "$name(%c)",[0], \@exprs, $opts);
$node->{prev_expr} = $exprs[0];
return $node;
} else {
# FIXME: we don't do \cS
# if (substr($text, 0, 1) eq "\cS") {
# # use op's parens
# return info_from_list($op, $self,[$name, substr($text, 1)],
# '', 'maybe_parens_unop_cS', {body => [$info]});
# } else
my $node;
if (substr($info->{text}, 0, 1) eq "(") {
# avoid looks-like-a-function trap with extra parens
# ('+' can lead to ambiguities)
$node = $self->info_from_template(
"$name(()) dup remove", $parent, "$name(%c)", [0], \@exprs, $opts);
} else {
$node = $self->info_from_template(
"$name <args>", $parent, "$name %c", [0], \@exprs, $opts);
}
$node->{prev_expr} = $exprs[0];
return $node;
}
Carp::confess("unhandled condition in maybe_parens_unop");
}
sub maybe_qualify {
my ($self,$prefix,$name) = @_;
my $v = ($prefix eq '$#' ? '@' : $prefix) . $name;
return $name if !$prefix || $name =~ /::/;
return $self->{'curstash'}.'::'. $name
if
$name =~ /^(?!\d)\w/ # alphabetic
&& $v !~ /^\$[ab]\z/ # not $a or $b
&& !$globalnames{$name} # not a global name
&& $self->{hints} & $strict_bits{vars} # strict vars
&& !$self->B::Deparse::lex_in_scope($v,1) # no "our"
or $self->B::Deparse::lex_in_scope($v); # conflicts with "my" variable
return $name;
}
# FIXME: need a way to pass in skipped_ops
# FIXME: see if we can move to some 5.xx-specific module
sub maybe_targmy
{
my($self, $op, $cx, $func, @args) = @_;
if ($op->private & OPpTARGET_MY) {
my $var = $self->padname($op->targ);
my $val = $func->($self, $op, 7, @args);
my @texts = ($var, '=', $val);
return $self->info_from_template("my", $op,
"%c = %c", [0, 1],
[$var, $val],
{maybe_parens => [$self, $cx, 7]});
} else {
return $self->$func($op, $cx, @args);
}
}
# Note: this is used in 5.28 and later versions only.
# FIXME: see if we can move to some 5.xx-specific module
sub maybe_var_attr {
my ($self, $op, $cx) = @_;
my @skipped_ops = ($op->first);
my $kid = $op->first->sibling; # skip pushmark
return if B::class($kid) eq 'NULL';
my $lop;
my $type;
# Extract out all the pad ops and entersub ops into
# @padops and @entersubops. Return if anything else seen.
( run in 0.757 second using v1.01-cache-2.11-cpan-39bf76dae61 )