use Carp 'cluck', 'croak';
use B qw(class main_root main_start main_cv svref_2object opnumber cstring
OPf_WANT OPf_WANT_VOID OPf_WANT_SCALAR OPf_WANT_LIST
- OPf_KIDS OPf_REF OPf_STACKED OPf_SPECIAL
+ OPf_KIDS OPf_REF OPf_STACKED OPf_SPECIAL OPf_MOD
OPpLVAL_INTRO OPpOUR_INTRO OPpENTERSUB_AMPER OPpSLICE OPpCONST_BARE
OPpTRANS_SQUASH OPpTRANS_DELETE OPpTRANS_COMPLEMENT OPpTARGET_MY
OPpCONST_ARYBASE OPpEXISTS_SUB OPpSORT_NUMERIC OPpSORT_INTEGER
elsif ($name eq 're') {
require re;
if ($val eq 'none') {
- $hint_bits &= ~re::bits(qw/taint eval asciirange/);
+ $hint_bits &= ~re::bits(qw/taint eval/);
next();
}
my @names;
if ($val eq 'all') {
- @names = qw/taint eval asciirange/;
+ @names = qw/taint eval/;
}
elsif (ref $val) {
@names = @$val;
return "XXX";
}
+sub pp_method_named {
+ cluck "unexpected OP_METHOD_NAMED";
+ return "XXX";
+}
+
sub pp_flip { # see also flop
cluck "unexpected OP_FLIP";
return "XXX";
($left, $right) = ($right, $left);
}
$left = $self->deparse_binop_left($op, $left, $prec);
- $left = "($left)" if $flags & LIST_CONTEXT && $left =~ /^\$/;
+ $left = "($left)" if $flags & LIST_CONTEXT
+ && $left !~ /^(my|our|local|)[\@\(]/;
$right = $self->deparse_binop_right($op, $right, $prec);
return $self->maybe_parens("$left $opname$eq $right", $cx, $prec);
}
BEGIN { eval "sub OP_CONST () {" . opnumber("const") . "}" }
BEGIN { eval "sub OP_STRINGIFY () {" . opnumber("stringify") . "}" }
BEGIN { eval "sub OP_RV2SV () {" . opnumber("rv2sv") . "}" }
+BEGIN { eval "sub OP_LIST () {" . opnumber("list") . "}" }
sub pp_null {
my $self = shift;
sub rv2x {
my $self = shift;
my($op, $cx, $type) = @_;
+
+ if (class($op) eq 'NULL' || !$op->can("first")) {
+ Carp::cluck("Unexpected op in pp_rv2x");
+ return 'XXX';
+ }
my $kid = $op->first;
my $str = $self->deparse($kid, 0);
return $self->stash_variable($type, $str) if is_scalar($kid);
}
# skip down to the old, ex-rv2cv
-sub pp_rv2cv { $_[0]->rv2x($_[1]->first->first->sibling, $_[2], "&") }
+sub pp_rv2cv {
+ my ($self, $op, $cx) = @_;
+ if (!null($op->first) && $op->first->name eq 'null' &&
+ $op->first->targ eq OP_LIST)
+ {
+ return $self->rv2x($op->first->first->sibling, $cx, "&")
+ }
+ else {
+ return $self->rv2x($op, $cx, "")
+ }
+}
sub pp_rv2av {
my $self = shift;
} else {
$obj = $kid;
$kid = $kid->sibling;
- for (; not null $kid->sibling; $kid = $kid->sibling) {
+ for (; !null ($kid->sibling) && $kid->name ne "method_named";
+ $kid = $kid->sibling) {
push @exprs, $self->deparse($kid, 6);
}
$meth = $kid;
my $prefix = "";
my $amper = "";
my($kid, @exprs);
- if ($op->flags & OPf_SPECIAL) {
+ if ($op->flags & OPf_SPECIAL && !($op->flags & OPf_MOD)) {
$prefix = "do ";
} elsif ($op->private & OPpENTERSUB_AMPER) {
$amper = "&";
}
$simple = 1; # only calls of named functions can be prototyped
$kid = $self->deparse($kid, 24);
- } elsif (is_scalar $kid->first) {
+ } elsif (is_scalar ($kid->first) && $kid->first->name ne 'rv2cv') {
$amper = "&";
$kid = $self->deparse($kid, 24);
} else {
return $str;
}
-# the same, but treat $|, $), $( and $ at the end of the string differently
-sub re_uninterp {
- my($str) = @_;
-
+{
+my $bal;
+BEGIN {
use re "eval";
# Matches any string which is balanced with respect to {braces}
- my $bal = qr(
+ $bal = qr(
(?:
[^\\{}]
| \\\\
| \{(??{$bal})\}
)*
)x;
+}
+
+# the same, but treat $|, $), $( and $ at the end of the string differently
+sub re_uninterp {
+ my($str) = @_;
$str =~ s/
( ^|\G # $1
return $str;
}
+# This is for regular expressions with the /x modifier
+# We have to leave comments unmangled.
sub re_uninterp_extended {
- my ($str) = @_;
- $str =~ s/^([^#]*)/re_uninterp($1)/emg;
+ my($str) = @_;
+
+ $str =~ s/
+ ( ^|\G # $1
+ | [^\\]
+ )
+
+ ( # $2
+ (?:\\\\)*
+ )
+
+ ( # $3
+ ( \(\?\??\{$bal\}\) # $4 (skip over (?{}) and (??{}) blocks)
+ | \#[^\n]* # (skip over comments)
+ )
+ | [\$\@]
+ (?!\||\)|\(|$)
+ | \\[uUlLQE]
+ )
+
+ /length($4) ? "$1$2$4" : "$1$2\\$3"/xeg;
+
return $str;
}
+}
# character escapes, but not delimiters that might need to be escaped
sub escape_str { # ASCII, UTF8
return $str;
}
+# For regexes with the /x modifier.
+# Leave whitespace unmangled.
sub escape_extended_re {
my($str) = @_;
$str =~ s/(.)/ord($1)>255 ? sprintf("\\x{%x}", ord($1)) : $1/eg;
my $first = $self->dq($op->first);
my $last = $self->dq($op->last);
- # Disambiguate "${foo}bar", "${foo}{bar}", "${foo}[1]"
+ # Disambiguate "${foo}bar", "${foo}{bar}", "${foo}[1]"
($last =~ /^[A-Z\\\^\[\]_?]/ &&
$first =~ s/([\$@])\^$/${1}{^}/) # "${^}W" etc
|| ($last =~ /^[{\[\w_]/ &&
} elsif ($type eq "concat") {
my $first = $self->re_dq($op->first, $extended);
my $last = $self->re_dq($op->last, $extended);
+
# Disambiguate "${foo}bar", "${foo}{bar}", "${foo}[1]"
- if ($last =~ /^[A-Z\\\^\[\]_?]/) {
- $first =~ s/([\$@])\^$/${1}{^}/;
- }
- elsif ($last =~ /^[{\[\w]/) {
- $first =~ s/([\$@])([A-Za-z_]\w*)$/${1}{$2}/;
- }
+ ($last =~ /^[A-Z\\\^\[\]_?]/ &&
+ $first =~ s/([\$@])\^$/${1}{^}/) # "${^}W" etc
+ || ($last =~ /^[{\[\w_]/ &&
+ $first =~ s/([\$@])([A-Za-z_]\w*)$/${1}{$2}/);
+
return $first . $last;
} elsif ($type eq "uc") {
return '\U' . $self->re_dq($op->first->sibling, $extended) . '\E';
$repl = $self->dq($repl);
}
}
+ my $extended = ($op->pmflags & PMf_EXTENDED);
if (null $kid) {
- $re = re_uninterp(escape_str(re_unback($op->precomp)));
+ my $unbacked = re_unback($op->precomp);
+ if ($extended) {
+ $re = re_uninterp_extended(escape_extended_re($unbacked));
+ }
+ else {
+ $re = re_uninterp(escape_str($unbacked));
+ }
} else {
- $re = $self->deparse($kid, 1);
+ ($re) = $self->regcomp($kid, 1, $extended);
}
$flags .= "e" if $op->pmflags & PMf_EVAL;
$flags .= "g" if $op->pmflags & PMf_GLOBAL;
$flags .= "m" if $op->pmflags & PMf_MULTILINE;
$flags .= "o" if $op->pmflags & PMf_KEEP;
$flags .= "s" if $op->pmflags & PMf_SINGLELINE;
- $flags .= "x" if $op->pmflags & PMf_EXTENDED;
+ $flags .= "x" if $extended;
$flags = $substwords{$flags} if $substwords{$flags};
if ($binop) {
return $self->maybe_parens("$var =~ s"
=item *
-Lvalue method calls are not yet fully supported. (Ordinary lvalue
-subroutine calls ought to be okay though.)
-
-=item *
-
If a keyword is over-ridden, and your program explicitly calls
the built-in version by using CORE::keyword, the output of B::Deparse
will not reflect this.
=item *
Constants (other than simple strings or numbers) don't work properly.
-Examples that fail include:
+Pathological examples that fail (and probably always will) include:
use constant E2BIG => ($!=7);
use constant x=>\$x; print x
+The following could (and should) be made to work:
+
+ use constant regex => qr/blah/;
+ print regex;
+
=item *
An input file that uses source filtering probably won't be deparsed into