This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Deparse crashed on argless sort()
[perl5.git] / dist / B-Deparse / Deparse.pm
index f400ed7..354e30f 100644 (file)
@@ -20,10 +20,11 @@ use B qw(class main_root main_start main_cv svref_2object opnumber perlstring
          CVf_METHOD CVf_LVALUE
         PMf_KEEP PMf_GLOBAL PMf_CONTINUE PMf_EVAL PMf_ONCE
         PMf_MULTILINE PMf_SINGLELINE PMf_FOLD PMf_EXTENDED);
-$VERSION = "1.10";
+$VERSION = '1.18';
 use strict;
 use vars qw/$AUTOLOAD/;
 use warnings ();
+require feature;
 
 BEGIN {
     # List version-specific constants here.
@@ -31,6 +32,7 @@ BEGIN {
     # be to fake up a dummy constant that will never actually be true.
     foreach (qw(OPpSORT_INPLACE OPpSORT_DESCEND OPpITER_REVERSED OPpCONST_NOVER
                OPpPAD_STATE PMf_SKIPWHITE RXf_SKIPWHITE
+               RXf_PMf_CHARSET RXf_PMf_KEEPCOPY
                CVf_LOCKED OPpREVERSE_INPLACE OPpSUBSTR_REPL_FIRST
                PMf_NONDESTRUCT OPpCONST_ARYBASE OPpEVAL_BYTES)) {
        eval { import B $_ };
@@ -217,7 +219,8 @@ BEGIN {
 # CV for current sub (or main program) being deparsed
 #
 # curcvlex:
-# Cached hash of lexical variables for curcv: keys are names,
+# Cached hash of lexical variables for curcv: keys are
+# names prefixed with "m" or "o" (representing my/our), and
 # each value is an array of pairs, indicating the cop_seq of scopes
 # in which a var of that name is valid.
 #
@@ -298,6 +301,7 @@ BEGIN {
 #  1             statement modifiers
 #  0.5           statements, but still print scopes as do { ... }
 #  0             statement level
+# -1             format body
 
 # Nonprinting characters with special meaning:
 # \cS - steal parens (see maybe_parens_unop)
@@ -469,7 +473,7 @@ sub begin_is_use {
 }
 
 sub stash_subs {
-    my ($self, $pack) = @_;
+    my ($self, $pack, $seen) = @_;
     my (@ret, $stash);
     if (!defined $pack) {
        $pack = '';
@@ -480,6 +484,10 @@ sub stash_subs {
        no strict 'refs';
        $stash = \%{"main::$pack"};
     }
+    return
+       if ($seen ||= {})->{
+           $INC{"overload.pm"} ? overload::StrVal($stash) : $stash
+          }++;
     my %stash = svref_2object($stash)->ARRAY;
     while (my ($key, $val) = each %stash) {
        my $class = class($val);
@@ -518,9 +526,7 @@ sub stash_subs {
                $self->todo($cv, 1);
            }
            if (class($val->HV) ne "SPECIAL" && $key =~ /::$/) {
-               $self->stash_subs($pack . $key)
-                   unless $pack eq '' && $key eq 'main::';
-                   # avoid infinite recursion
+               $self->stash_subs($pack . $key, $seen);
            }
        }
     }
@@ -704,6 +710,11 @@ sub coderef2text {
     return $self->indent($self->deparse_sub(svref_2object($sub)));
 }
 
+my %strict_bits = do {
+    local $^H;
+    map +($_ => strict::bits($_)), qw/refs subs vars/
+};
+
 sub ambient_pragmas {
     my $self = shift;
     my ($arybase, $hint_bits, $warning_bits, $hinthash) = (0, 0);
@@ -716,7 +727,7 @@ sub ambient_pragmas {
            require strict;
 
            if ($val eq 'none') {
-               $hint_bits &= ~strict::bits(qw/refs subs vars/);
+               $hint_bits &= $strict_bits{$_} for qw/refs subs vars/;
                next();
            }
 
@@ -730,7 +741,7 @@ sub ambient_pragmas {
            else {
                @names = split' ', $val;
            }
-           $hint_bits |= strict::bits(@names);
+           $hint_bits |= $strict_bits{$_} for @names;
        }
 
        elsif ($name eq '$[') {
@@ -885,7 +896,7 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
            for(my$o=$lineseq->first; $$o; $o=$o->sibling) {
                push @ops, $o;
            }
-           $body = $self->lineseq(undef, @ops).";";
+           $body = $self->lineseq(undef, 0, @ops).";";
            my $scope_en = $self->find_scope_en($lineseq);
            if (defined $scope_en) {
                my $subs = join"", $self->seq_subs($scope_en);
@@ -929,7 +940,8 @@ sub deparse_format {
        push @text, "\f".$self->const_sv($kid)->PV;
        $kid = $kid->sibling;
        for (; not null $kid; $kid = $kid->sibling) {
-           push @exprs, $self->deparse($kid, 0);
+           push @exprs, $self->deparse($kid, -1);
+           $exprs[-1] =~ s/;\z//;
        }
        push @text, "\f".join(", ", @exprs)."\n" if @exprs;
        $op = $op->sibling;
@@ -1129,7 +1141,7 @@ sub DESTROY {}    #       Do not AUTOLOAD
 # any subroutine declarations to the deparsed ops, otherwise we
 # append appropriate declarations.
 sub lineseq {
-    my($self, $root, @ops) = @_;
+    my($self, $root, $cx, @ops) = @_;
     my($expr, @exprs);
 
     my $out_cop = $self->{'curcop'};
@@ -1150,12 +1162,13 @@ sub lineseq {
     $self->walk_lineseq($root, \@ops,
                       sub { push @exprs, $_[0]} );
 
-    my $body = join(";\n", grep {length} @exprs);
+    my $sep = $cx ? '; ' : ";\n";
+    my $body = join($sep, grep {length} @exprs);
     my $subs = "";
     if (defined $root && defined $limit_seq && !$self->{'in_format'}) {
        $subs = join "\n", $self->seq_subs($limit_seq);
     }
-    return join(";\n", grep {length} $body, $subs);
+    return join($sep, grep {length} $body, $subs);
 }
 
 sub scopeop {
@@ -1190,9 +1203,9 @@ sub scopeop {
        push @kids, $kid;
     }
     if ($cx > 0) { # inside an expression, (a do {} while for lineseq)
-       return "do {\n\t" . $self->lineseq($op, @kids) . "\n\b}";
+       return "do {\n\t" . $self->lineseq($op, 0, @kids) . "\n\b}";
     } else {
-       my $lineseq = $self->lineseq($op, @kids);
+       my $lineseq = $self->lineseq($op, $cx, @kids);
        return (length ($lineseq) ? "$lineseq;" : "");
     }
 }
@@ -1252,29 +1265,32 @@ BEGIN { map($globalnames{$_}++, "SIG", "STDIN", "STDOUT", "STDERR", "INC",
 sub gv_name {
     my $self = shift;
     my $gv = shift;
+    my $raw = shift;
 Carp::confess() unless ref($gv) eq "B::GV";
     my $stash = $gv->STASH->NAME;
-    my $name = $gv->SAFENAME;
+    my $name = $raw ? $gv->NAME : $gv->SAFENAME;
     if ($stash eq 'main' && $name =~ /^::/) {
        $stash = '::';
     }
-    elsif (($stash eq 'main' && $globalnames{$name})
+    elsif (($stash eq 'main'
+           && ($globalnames{$name} || $name =~ /^[^A-Za-z_:]/))
        or ($stash eq $self->{'curstash'} && !$globalnames{$name}
            && ($stash eq 'main' || $name !~ /::/))
-       or $name =~ /^[^A-Za-z_:]/)
+         )
     {
        $stash = "";
     } else {
        $stash = $stash . "::";
     }
-    if ($name =~ /^(\^..|{)/) {
+    if (!$raw and $name =~ /^(\^..|{)/) {
         $name = "{$name}";       # ${^WARNING_BITS}, etc and ${
     }
     return $stash . $name;
 }
 
 # Return the name to use for a stash variable.
-# If a lexical with the same name is in scope, it may need to be
+# If a lexical with the same name is in scope, or
+# if strictures are enabled, it may need to be
 # fully-qualified.
 sub stash_variable {
     my ($self, $prefix, $name, $cx) = @_;
@@ -1298,13 +1314,43 @@ sub stash_variable {
       }
     }
 
+    return $prefix . $self->maybe_qualify($prefix, $name);
+}
+
+# Return just the name, without the prefix.  It may be returned as a quoted
+# string.  The second return value is a boolean indicating that.
+sub stash_variable_name {
+    my($self, $prefix, $gv) = @_;
+    my $name = $self->gv_name($gv, 1);
+    $name = $self->maybe_qualify($prefix,$name);
+    if ($name =~ /^(?:\S|(?!\d)[\ca-\cz]?(?:\w|::)*|\d+)\z/) {
+       $name =~ s/^([\ca-\cz])/'^'.($1|'@')/e;
+       $name =~ /^(\^..|{)/ and $name = "{$name}";
+       return $name, 0; # not quoted
+    }
+    else {
+       single_delim("q", "'", $name), 1;
+    }
+}
+
+sub maybe_qualify {
+    my ($self,$prefix,$name) = @_;
     my $v = ($prefix eq '$#' ? '@' : $prefix) . $name;
-    return $prefix .$self->{'curstash'}.'::'. $name if $self->lex_in_scope($v);
-    return "$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->lex_in_scope($v,1)   # no "our"
+      or $self->lex_in_scope($v);        # conflicts with "my" variable
+    return $name;
 }
 
 sub lex_in_scope {
-    my ($self, $name) = @_;
+    my ($self, $name, $our) = @_;
+    substr $name, 0, 0, = $our ? 'o' : 'm'; # our/my
     $self->populate_curcvlex() if !defined $self->{'curcvlex'};
 
     return 0 if !defined($self->{'curcop'});
@@ -1328,7 +1374,6 @@ sub populate_curcvlex {
 
        for (my $i=0; $i<@ns; ++$i) {
            next if class($ns[$i]) eq "SPECIAL";
-           next if $ns[$i]->FLAGS & SVpad_OUR;  # Skip "our" vars
            if (class($ns[$i]) eq "PV") {
                # Probably that pesky lexical @_
                next;
@@ -1339,7 +1384,9 @@ sub populate_curcvlex {
                    ? (0, 999999)
                    : ($ns[$i]->COP_SEQ_RANGE_LOW, $ns[$i]->COP_SEQ_RANGE_HIGH);
 
-           push @{$self->{'curcvlex'}{$name}}, [$seq_st, $seq_en];
+           push @{$self->{'curcvlex'}{
+                       ($ns[$i]->FLAGS & SVpad_OUR ? 'o' : 'm') . $name
+                 }}, [$seq_st, $seq_en];
        }
     }
 }
@@ -1405,6 +1452,14 @@ sub seq_subs {
     return @text;
 }
 
+sub _features_from_bundle {
+    my ($hints, $hh) = @_;
+    foreach (@{$feature::feature_bundle{@feature::hint_bundles[$hints >> $feature::hint_shift]}}) {
+       $hh->{$feature::feature{$_}} = 1;
+    }
+    return $hh;
+}
+
 # Notice how subs and formats are inserted between statements here;
 # also $[ assignments and pragmas.
 sub pp_nextstate {
@@ -1446,18 +1501,47 @@ sub pp_nextstate {
     }
 
     my $hints = $] < 5.008009 ? $op->private : $op->hints;
+    my $old_hints = $self->{'hints'};
     if ($self->{'hints'} != $hints) {
        push @text, declare_hints($self->{'hints'}, $hints);
        $self->{'hints'} = $hints;
     }
 
-    if ($] > 5.009 &&
-       @text != push @text, declare_hinthash(
-           $self->{'hinthash'}, $op->hints_hash->HASH,
-           $self->{indent_size}
-       )
-    ) {
-       $self->{'hinthash'} = $op->hints_hash->HASH;
+    my $newhh;
+    if ($] > 5.009) {
+       $newhh = $op->hints_hash->HASH;
+    }
+
+    if ($] >= 5.015006) {
+       # feature bundle hints
+       my $from = $old_hints & $feature::hint_mask;
+       my $to   = $    hints & $feature::hint_mask;
+       if ($from != $to) {
+           if ($to == $feature::hint_mask) {
+               if ($self->{'hinthash'}) {
+                   delete $self->{'hinthash'}{$_}
+                       for grep /^feature_/, keys %{$self->{'hinthash'}};
+               }
+               else { $self->{'hinthash'} = {} }
+               $self->{'hinthash'}
+                   = _features_from_bundle($from, $self->{'hinthash'});
+           }
+           else {
+               my $bundle =
+                   $feature::hint_bundles[$to >> $feature::hint_shift];
+               $bundle =~ s/(\d[13579])\z/$1+1/e; # 5.11 => 5.12
+               push @text, "no feature;\n",
+                           "use feature ':$bundle';\n";
+           }
+       }
+    }
+
+    if ($] > 5.009) {
+       push @text, declare_hinthash(
+           $self->{'hinthash'}, $newhh,
+           $self->{indent_size}, $self->{hints},
+       );
+       $self->{'hinthash'} = $newhh;
     }
 
     # This should go after of any branches that add statements, to
@@ -1504,14 +1588,26 @@ my %ignored_hints = (
     'open<' => 1,
     'open>' => 1,
     ':'     => 1,
+    'strict/refs' => 1,
+    'strict/subs' => 1,
+    'strict/vars' => 1,
 );
 
+my %rev_feature;
+
 sub declare_hinthash {
-    my ($from, $to, $indent) = @_;
+    my ($from, $to, $indent, $hints) = @_;
+    my $doing_features =
+       ($hints & $feature::hint_mask) == $feature::hint_mask;
     my @decls;
-    for my $key (keys %$to) {
+    my @features;
+    my @unfeatures; # bugs?
+    for my $key (sort keys %$to) {
        next if $ignored_hints{$key};
+       my $is_feature = $key =~ /^feature_/ && $^V ge 5.15.6;
+       next if $is_feature and not $doing_features;
        if (!exists $from->{$key} or $from->{$key} ne $to->{$key}) {
+           push(@features, $key), next if $is_feature;
            push @decls,
                qq(\$^H{) . single_delim("q", "'", $key) . qq(} = )
              . (
@@ -1522,21 +1618,47 @@ sub declare_hinthash {
              . qq(;);
        }
     }
-    for my $key (keys %$from) {
+    for my $key (sort keys %$from) {
        next if $ignored_hints{$key};
+       my $is_feature = $key =~ /^feature_/ && $^V ge 5.15.6;
+       next if $is_feature and not $doing_features;
        if (!exists $to->{$key}) {
+           push(@unfeatures, $key), next if $is_feature;
            push @decls, qq(delete \$^H{'$key'};);
        }
     }
-    @decls or return;
-    return join("\n" . (" " x $indent), "BEGIN {", @decls) . "\n}\n";
+    my @ret;
+    if (@features || @unfeatures) {
+       if (!%rev_feature) { %rev_feature = reverse %feature::feature }
+    }
+    if (@features) {
+       push @ret, "use feature "
+                . join(", ", map "'$rev_feature{$_}'", @features) . ";\n";
+    }
+    if (@unfeatures) {
+       push @ret, "no feature "
+                . join(", ", map "'$rev_feature{$_}'", @unfeatures)
+                . ";\n";
+    }
+    @decls and
+       push @ret,
+            join("\n" . (" " x $indent), "BEGIN {", @decls) . "\n}\n";
+    return @ret;
 }
 
 sub hint_pragmas {
     my ($bits) = @_;
-    my @pragmas;
+    my (@pragmas, @strict);
     push @pragmas, "integer" if $bits & 0x1;
-    push @pragmas, "strict 'refs'" if $bits & 0x2;
+    for (sort keys %strict_bits) {
+       push @strict, "'$_'" if $bits & $strict_bits{$_};
+    }
+    if (@strict == keys %strict_bits) {
+       push @pragmas, "strict";
+    }
+    elsif (@strict) {
+       push @pragmas, "strict " . join ', ', @strict;
+    }
     push @pragmas, "bytes" if $bits & 0x8;
     return @pragmas;
 }
@@ -1556,6 +1678,7 @@ my %feature_keywords = (
     break   => 'switch',
     evalbytes=>'evalbytes',
     __SUB__ => '__SUB__',
+   fc       => 'fc',
 );
 
 sub keyword {
@@ -1563,9 +1686,15 @@ sub keyword {
     my $name = shift;
     return $name if $name =~ /^CORE::/; # just in case
     if (exists $feature_keywords{$name}) {
+       my $hh;
+       my $hints = $self->{hints} & $feature::hint_mask;
+       if ($hints && $hints != $feature::hint_mask) {
+           $hh = _features_from_bundle($hints);
+       }
+       elsif ($hints) { $hh = $self->{'hinthash'} }
        return "CORE::$name"
-        if !$self->{'hinthash'}
-        || !$self->{'hinthash'}{"feature_$feature_keywords{$name}"}
+        if !$hh
+        || !$hh->{"feature_$feature_keywords{$name}"}
     }
     if (
       $name !~ /^(?:chom?p|do|exec|glob|s(?:elect|ystem))\z/
@@ -1629,7 +1758,13 @@ sub pfixop {
     my($op, $cx, $name, $prec, $flags) = (@_, 0);
     my $kid = $op->first;
     $kid = $self->deparse($kid, $prec);
-    return $self->maybe_parens(($flags & POSTFIX) ? "$kid$name" : "$name$kid",
+    return $self->maybe_parens(($flags & POSTFIX)
+                                ? "$kid$name"
+                                  # avoid confusion with filetests
+                                : $name eq '-'
+                                  && $kid =~ /^[a-zA-Z](?!\w)/
+                                       ? "$name($kid)"
+                                       : "$name$kid",
                               $cx, $prec);
 }
 
@@ -1660,7 +1795,7 @@ sub pp_not {
     my $self = shift;
     my($op, $cx) = @_;
     if ($cx <= 4) {
-       $self->pfixop($op, $cx, $self->keyword("not")." ", 4);
+       $self->listop($op, $cx, "not", $op->first);
     } else {
        $self->pfixop($op, $cx, "!", 21);       
     }
@@ -1692,8 +1827,10 @@ sub unop {
        }   
        return $self->maybe_parens_unop($name, $kid, $cx);
     } else {
-       return $self->keyword($name)
-         . ($op->flags & OPf_SPECIAL ? "()" : "");
+       return $self->maybe_parens(
+           $self->keyword($name) . ($op->flags & OPf_SPECIAL ? "()" : ""),
+           $cx, 16,
+       );
     }
 }
 
@@ -1881,7 +2018,10 @@ sub pp_require {
     } else {   
        $self->unop(
            $op, $cx,
-           $op->first->private & OPpCONST_NOVER ? "no" : $opname,
+           $op->first->name eq 'const'
+            && $op->first->private & OPpCONST_NOVER
+                ? "no"
+                : $opname,
            1, # llafr does not apply
        );
     }
@@ -2008,6 +2148,7 @@ sub pp_lcfirst { dq_unop(@_, "lcfirst") }
 sub pp_uc { dq_unop(@_, "uc") }
 sub pp_lc { dq_unop(@_, "lc") }
 sub pp_quotemeta { maybe_targmy(@_, \&dq_unop, "quotemeta") }
+sub pp_fc { dq_unop(@_, "fc") }
 
 sub loopex {
     my $self = shift;
@@ -2017,17 +2158,17 @@ sub loopex {
     } elsif (class($op) eq "OP") {
        # no-op
     } elsif (class($op) eq "UNOP") {
-       (my $kid = $self->deparse($op->first, 16)) =~ s/^\cS//;
+       (my $kid = $self->deparse($op->first, 7)) =~ s/^\cS//;
        $name .= " $kid";
     }
-    return $self->maybe_parens($name, $cx, 16);
+    return $self->maybe_parens($name, $cx, 7);
 }
 
 sub pp_last { loopex(@_, "last") }
 sub pp_next { loopex(@_, "next") }
 sub pp_redo { loopex(@_, "redo") }
 sub pp_goto { loopex(@_, "goto") }
-sub pp_dump { loopex(@_, $_[0]->keyword("dump")) }
+sub pp_dump { loopex(@_, "CORE::dump") }
 
 sub ftst {
     my $self = shift;
@@ -2358,21 +2499,41 @@ sub pp_andassign { logassignop(@_, "&&=") }
 sub pp_orassign  { logassignop(@_, "||=") }
 sub pp_dorassign { logassignop(@_, "//=") }
 
+sub rv2gv_or_string {
+    my($self,$op) = @_;
+    if ($op->name eq "gv") { # could be open("open") or open("###")
+       my($name,$quoted) =
+           $self->stash_variable_name("", $self->gv_or_padgv($op));
+       $quoted ? $name : "*$name";
+    }
+    else {
+       $self->deparse($op, 6);
+    }
+}
+
 sub listop {
     my $self = shift;
     my($op, $cx, $name, $kid, $nollafr) = @_;
     my(@exprs);
     my $parens = ($cx >= 5) || $self->{'parens'};
     $kid ||= $op->first->sibling;
-    return $self->keyword($name) if null $kid;
+    # If there are no arguments, add final parentheses (or parenthesize the
+    # whole thing if the llafr does not apply) to account for cases like
+    # (return)+1 or setpgrp()+1.  When the llafr does not apply, we use a
+    # precedence of 6 (< comma), as "return, 1" does not need parentheses.
+    if (null $kid) {
+       return $nollafr
+               ? $self->maybe_parens($self->keyword($name), $cx, 7)
+               : $self->keyword($name) . '()' x (7 < $cx);
+    }
     my $first;
     $name = "socketpair" if $name eq "sockpair";
     my $fullname = $self->keyword($name);
     my $proto = prototype("CORE::$name");
     if (defined $proto
        && $proto =~ /^;?\*/
-       && $kid->name eq "rv2gv") {
-       $first = $self->deparse($kid->first, 6);
+       && $kid->name eq "rv2gv" && !($kid->private & OPpLVAL_INTRO)) {
+       $first = $self->rv2gv_or_string($kid->first);
     }
     else {
        $first = $self->deparse($kid, 6);
@@ -2384,8 +2545,9 @@ sub listop {
        if not $parens and not $nollafr and substr($first, 0, 1) eq "(";
     push @exprs, $first;
     $kid = $kid->sibling;
-    if (defined $proto && $proto =~ /^\*\*/ && $kid->name eq "rv2gv") {
-       push @exprs, $self->deparse($kid->first, 6);
+    if (defined $proto && $proto =~ /^\*\*/ && $kid->name eq "rv2gv"
+        && !($kid->private & OPpLVAL_INTRO)) {
+       push @exprs, $first = $self->rv2gv_or_string($kid->first);
        $kid = $kid->sibling;
     }
     for (; !null($kid); $kid = $kid->sibling) {
@@ -2591,6 +2753,7 @@ sub indirop {
        }
     } elsif (
        !$indir && $name eq "sort"
+      && !null($op->first->sibling)
       && $op->first->sibling->name eq 'entersub'
     ) {
        # We cannot say sort foo(bar), as foo will be interpreted as a
@@ -2815,7 +2978,7 @@ sub loop_common {
            $var = "\$" . $self->deparse($var, 1);
        }
        $body = $kid->first->first->sibling; # skip OP_AND and OP_ITER
-       if (!is_state $body->first and $body->first->name ne "stub") {
+       if (!is_state $body->first and $body->first->name !~ /^(?:stub|leave|scope)$/) {
            confess unless $var eq '$_';
            $body = $body->first;
            return $self->deparse($body, 2) . " foreach ($ary)";
@@ -2852,7 +3015,7 @@ sub loop_common {
        for (; $$state != $$cont; $state = $state->sibling) {
            push @states, $state;
        }
-       $body = $self->lineseq(undef, @states);
+       $body = $self->lineseq(undef, 0, @states);
        if (defined $cond and not is_scope $cont and $self->{'expand'} < 3) {
            $head = "for ($init; $cond; " . $self->deparse($cont, 1) .") ";
            $cont = "\cK";
@@ -3012,10 +3175,8 @@ sub pp_aelemfast {
     return $self->pp_aelemfast_lex(@_) if ($op->flags & OPf_SPECIAL);
 
     my $gv = $self->gv_or_padgv($op);
-    my $name = $self->gv_name($gv);
-    $name = $self->{'curstash'}."::$name"
-       if $name !~ /::/ && $self->lex_in_scope('@'.$name);
-    $name = '$' . $name;
+    my($name,$quoted) = $self->stash_variable_name('@',$gv);
+    $name = $quoted ? "$name->" : '$' . $name;
     return $name . "[" .  ($op->private + $self->{'arybase'}) . "]";
 }
 
@@ -3138,13 +3299,15 @@ sub elem_or_slice_array_name
     } elsif (is_scope($array)) { # ${expr}[0]
        return "{" . $self->deparse($array, 0) . "}";
     } elsif ($array->name eq "gv") {
-       $array = $self->gv_name($self->gv_or_padgv($array));
-       if ($array !~ /::/) {
-           my $prefix = ($left eq '[' ? '@' : '%');
-           $array = $self->{curstash}.'::'.$array
-               if $self->lex_in_scope($prefix . $array);
+       ($array, my $quoted) =
+           $self->stash_variable_name(
+               $left eq '[' ? '@' : '%', $self->gv_or_padgv($array)
+           );
+       if (!$allow_arrow && $quoted) {
+           # This cannot happen.
+           die "Invalid variable name $array for slice";
        }
-       return $array;
+       return $quoted ? "$array->" : $array;
     } elsif (!$allow_arrow || is_scalar $array) { # $x[0], $$x[0], ...
        return $self->deparse($array, 24);
     } else {
@@ -3202,7 +3365,8 @@ sub elem {
     }
     if (my $array_name=$self->elem_or_slice_array_name
            ($array, $left, $padname, 1)) {
-       return "\$" . $array_name . $left . $idx . $right;
+       return ($array_name =~ /->\z/ ? $array_name : "\$" . $array_name)
+             . $left . $idx . $right;
     } else {
        # $x[20][3]{hi} or expr->[20]
        my $arrow = is_subscriptable($array) ? "" : "->";
@@ -3514,6 +3678,7 @@ sub pp_entersub {
        $args = join(", ", map($self->deparse($_, 6), @exprs));
     }
     if ($prefix or $amper) {
+       if ($kid eq '&') { $kid = "{$kid}" } # &{&} cannot be written as &&
        if ($op->flags & OPf_STACKED) {
            return $prefix . $amper . $kid . "(" . $args . ")";
        } else {
@@ -3857,14 +4022,12 @@ sub const {
            return "{" . join(", ", @elts) . "}";
        } elsif (class($ref) eq "CV") {
            BEGIN {
-# Commented out until after 5.15.6
-#              if ($] > 5.0150051) {
+               if ($] > 5.0150051) {
                    require overloading;
                    unimport overloading;
-#              }
+               }
            }
-           # Remove the 1|| after 5.15.6
-           if ((1||$] > 5.0150051) && $self->{curcv} &&
+           if ($] > 5.0150051 && $self->{curcv} &&
                 $self->{curcv}->object_2svref == $ref->object_2svref) {
                return $self->keyword("__SUB__");
            }
@@ -3956,6 +4119,8 @@ sub dq {
        return '\l' . $self->dq($op->first->sibling);
     } elsif ($type eq "quotemeta") {
        return '\Q' . $self->dq($op->first->sibling) . '\E';
+    } elsif ($type eq "fc") {
+       return '\F' . $self->dq($op->first->sibling) . '\E';
     } elsif ($type eq "join") {
        return $self->deparse($op->last, 26); # was join($", @ary)
     } else {
@@ -4277,10 +4442,14 @@ sub re_dq {
        return '\l' . $self->re_dq($op->first->sibling, $extended);
     } elsif ($type eq "quotemeta") {
        return '\Q' . $self->re_dq($op->first->sibling, $extended) . '\E';
+    } elsif ($type eq "fc") {
+       return '\F' . $self->re_dq($op->first->sibling, $extended) . '\E';
     } elsif ($type eq "join") {
        return $self->deparse($op->last, 26); # was join($", @ary)
     } else {
-       return $self->deparse($op, 26);
+       my $ret = $self->deparse($op, 26);
+       $ret =~ s/^\$([(|)])\z/\${$1}/; # $( $| $) need braces
+       return $ret;
     }
 }
 
@@ -4289,10 +4458,10 @@ sub pure_string {
     return 0 if null $op;
     my $type = $op->name;
 
-    if ($type eq 'const') {
+    if ($type eq 'const' || $type eq 'av2arylen') {
        return 1;
     }
-    elsif ($type =~ /^[ul]c(first)?$/ || $type eq 'quotemeta') {
+    elsif ($type =~ /^(?:[ul]c(first)?|fc)$/ || $type eq 'quotemeta') {
        return $self->pure_string($op->first->sibling);
     }
     elsif ($type eq 'join') {
@@ -4314,9 +4483,12 @@ sub pure_string {
        return 1;
     }
     elsif ($type eq "null" and $op->can('first') and not null $op->first and
-          $op->first->name eq "null" and $op->first->can('first')
+         ($op->first->name eq "null" and $op->first->can('first')
           and not null $op->first->first and
-          $op->first->first->name eq "aelemfast") {
+          $op->first->first->name eq "aelemfast"
+          or
+          $op->first->name =~ /^aelemfast(?:_lex)?\z/
+         )) {
        return 1;
     }
     else {
@@ -4355,6 +4527,38 @@ sub pp_regcomp {
     return (($self->regcomp($op, $cx, 0))[0]);
 }
 
+sub re_flags {
+    my ($self, $op) = @_;
+    my $flags = '';
+    my $pmflags = $op->pmflags;
+    $flags .= "g" if $pmflags & PMf_GLOBAL;
+    $flags .= "i" if $pmflags & PMf_FOLD;
+    $flags .= "m" if $pmflags & PMf_MULTILINE;
+    $flags .= "o" if $pmflags & PMf_KEEP;
+    $flags .= "s" if $pmflags & PMf_SINGLELINE;
+    $flags .= "x" if $pmflags & PMf_EXTENDED;
+    $flags .= "p" if $pmflags & RXf_PMf_KEEPCOPY;
+    if (my $charset = $pmflags & RXf_PMf_CHARSET) {
+       # Hardcoding this is fragile, but B does not yet export the
+       # constants we need.
+       $flags .= qw(d l u a aa)[$charset >> 5]
+    }
+    # The /d flag is indicated by 0; only show it if necessary.
+    elsif ($self->{hinthash} and
+            $self->{hinthash}{reflags_charset}
+           || $self->{hinthash}{feature_unicode}
+       or $self->{hints} & $feature::hint_mask
+         && ($self->{hints} & $feature::hint_mask)
+              != $feature::hint_mask
+         && do {
+               $self->{hints} & $feature::hint_uni8bit;
+            }
+  ) {
+       $flags .= 'd';
+    }
+    $flags;
+}
+
 # osmic acid -- see osmium tetroxide
 
 my %matchwords;
@@ -4373,7 +4577,8 @@ sub matchop {
        $kid = $kid->sibling;
     }
     my $quote = 1;
-    my $extended = ($op->pmflags & PMf_EXTENDED);
+    my $pmflags = $op->pmflags;
+    my $extended = ($pmflags & PMf_EXTENDED);
     my $rhs_bound_to_defsv;
     if (null $kid) {
        my $unbacked = re_unback($op->precomp);
@@ -4386,22 +4591,21 @@ sub matchop {
        carp("found ".$kid->name." where regcomp expected");
     } else {
        ($re, $quote) = $self->regcomp($kid, 21, $extended);
-       my $matchop = $kid->first->first;
+       my $matchop = $kid->first;
+       if ($matchop->name eq 'regcrest') {
+           $matchop = $matchop->first;
+       }
        if ($matchop->name =~ /^(?:match|transr?|subst)\z/
           && $matchop->flags & OPf_SPECIAL) {
            $rhs_bound_to_defsv = 1;
        }
     }
     my $flags = "";
-    $flags .= "c" if $op->pmflags & PMf_CONTINUE;
-    $flags .= "g" if $op->pmflags & PMf_GLOBAL;
-    $flags .= "i" if $op->pmflags & PMf_FOLD;
-    $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 .= "c" if $pmflags & PMf_CONTINUE;
+    $flags .= $self->re_flags($op);
+    $flags = join '', sort split //, $flags;
     $flags = $matchwords{$flags} if $matchwords{$flags};
-    if ($op->pmflags & PMf_ONCE) { # only one kind of delimiter works here
+    if ($pmflags & PMf_ONCE) { # only one kind of delimiter works here
        $re =~ s/\?/\\?/g;
        $re = "?$re?";
     } elsif ($quote) {
@@ -4454,8 +4658,11 @@ sub pp_split {
 
     # handle special case of split(), and split(' ') that compiles to /\s+/
     # Under 5.10, the reflags may be undef if the split regexp isn't a constant
+    # Under 5.17.5+, the special flag is on split itself.
     $kid = $op->first;
-    if ( $kid->flags & OPf_SPECIAL
+    if ( $op->flags & OPf_SPECIAL
+       or
+        $kid->flags & OPf_SPECIAL
         and ( $] < 5.009 ? $kid->pmflags & PMf_SKIPWHITE()
              : ($kid->reflags || 0) & RXf_SKIPWHITE() ) ) {
        $exprs[0] = "' '";
@@ -4477,7 +4684,7 @@ my %substwords;
 map($substwords{join "", sort split //, $_} = $_, 'ego', 'egoism', 'em',
     'es', 'ex', 'exes', 'gee', 'go', 'goes', 'ie', 'ism', 'iso', 'me',
     'meese', 'meso', 'mig', 'mix', 'os', 'ox', 'oxime', 'see', 'seem',
-    'seg', 'sex', 'sig', 'six', 'smog', 'sog', 'some', 'xi',
+    'seg', 'sex', 'sig', 'six', 'smog', 'sog', 'some', 'xi', 'rogue',
     'sir', 'rise', 'smore', 'more', 'seer', 'rome', 'gore', 'grim', 'grime',
     'or', 'rose', 'rosie');
 
@@ -4492,6 +4699,7 @@ sub pp_subst {
        $kid = $kid->sibling;
     }
     my $flags = "";
+    my $pmflags = $op->pmflags;
     if (null($op->pmreplroot)) {
        $repl = $self->dq($kid);
        $kid = $kid->sibling;
@@ -4501,13 +4709,13 @@ sub pp_subst {
            $repl = $repl->first;
            $flags .= "e";
        }
-       if ($op->pmflags & PMf_EVAL) {
+       if ($pmflags & PMf_EVAL) {
            $repl = $self->deparse($repl->first, 0);
        } else {
            $repl = $self->dq($repl);   
        }
     }
-    my $extended = ($op->pmflags & PMf_EXTENDED);
+    my $extended = ($pmflags & PMf_EXTENDED);
     if (null $kid) {
        my $unbacked = re_unback($op->precomp);
        if ($extended) {
@@ -4519,14 +4727,10 @@ sub pp_subst {
     } else {
        ($re) = $self->regcomp($kid, 1, $extended);
     }
-    $flags .= "e" if $op->pmflags & PMf_EVAL;
-    $flags .= "r" if $op->pmflags & PMf_NONDESTRUCT;
-    $flags .= "g" if $op->pmflags & PMf_GLOBAL;
-    $flags .= "i" if $op->pmflags & PMf_FOLD;
-    $flags .= "m" if $op->pmflags & PMf_MULTILINE;
-    $flags .= "o" if $op->pmflags & PMf_KEEP;
-    $flags .= "s" if $op->pmflags & PMf_SINGLELINE;
-    $flags .= "x" if $extended;
+    $flags .= "r" if $pmflags & PMf_NONDESTRUCT;
+    $flags .= "e" if $pmflags & PMf_EVAL;
+    $flags .= $self->re_flags($op);
+    $flags = join '', sort split //, $flags;
     $flags = $substwords{$flags} if $substwords{$flags};
     if ($binop) {
        return $self->maybe_parens("$var =~ s"
@@ -4553,18 +4757,18 @@ B<perl> B<-MO=Deparse>[B<,-d>][B<,-f>I<FILE>][B<,-p>][B<,-q>][B<,-l>]
 
 B::Deparse is a backend module for the Perl compiler that generates
 perl source code, based on the internal compiled structure that perl
-itself creates after parsing a program. The output of B::Deparse won't
+itself creates after parsing a program.  The output of B::Deparse won't
 be exactly the same as the original source, since perl doesn't keep
 track of comments or whitespace, and there isn't a one-to-one
 correspondence between perl's syntactical constructions and their
-compiled form, but it will often be close. When you use the B<-p>
+compiled form, but it will often be close.  When you use the B<-p>
 option, the output also includes parentheses even when they are not
 required by precedence, which can make it easy to see if perl is
 parsing your expressions the way you intended.
 
 While B::Deparse goes to some lengths to try to figure out what your
 original program was doing, some parts of the language can still trip
-it up; it still fails even on some parts of Perl's own test suite. If
+it up; it still fails even on some parts of Perl's own test suite.  If
 you encounter a failure other than the most common ones described in
 the BUGS section below, you can help contribute to B::Deparse's
 ongoing development by submitting a bug report with a small
@@ -4581,7 +4785,7 @@ the '-MO=Deparse', separated by a comma but not any white space.
 
 Output data values (when they appear as constants) using Data::Dumper.
 Without this option, B::Deparse will use some simple routines of its
-own for the same purpose. Currently, Data::Dumper is better for some
+own for the same purpose.  Currently, Data::Dumper is better for some
 kinds of data (such as complex structures with sharing and
 self-reference) while the built-in routines are better for others
 (such as odd floating-point values).
@@ -4589,8 +4793,9 @@ self-reference) while the built-in routines are better for others
 =item B<-f>I<FILE>
 
 Normally, B::Deparse deparses the main code of a program, and all the subs
-defined in the same file. To include subs defined in other files, pass the
-B<-f> option with the filename. You can pass the B<-f> option several times, to
+defined in the same file.  To include subs defined in
+other files, pass the B<-f> option with the filename.
+You can pass the B<-f> option several times, to
 include more than one secondary file.  (Most of the time you don't want to
 use it at all.)  You can also use this option to include subs which are
 defined in the scope of a B<#line> directive with two parameters.
@@ -4602,11 +4807,11 @@ locations of the original code.
 
 =item B<-p>
 
-Print extra parentheses. Without this option, B::Deparse includes
+Print extra parentheses.  Without this option, B::Deparse includes
 parentheses in its output only when they are needed, based on the
-structure of your program. With B<-p>, it uses parentheses (almost)
-whenever they would be legal. This can be useful if you are used to
-LISP, or if you want to see how perl parses your input. If you say
+structure of your program.  With B<-p>, it uses parentheses (almost)
+whenever they would be legal.  This can be useful if you are used to
+LISP, or if you want to see how perl parses your input.  If you say
 
     if ($var & 0x7f == 65) {print "Gimme an A!"}
     print ($which ? $a : $b), "\n";
@@ -4625,8 +4830,8 @@ perl optimized away a constant value).
 
 =item B<-P>
 
-Disable prototype checking. With this option, all function calls are
-deparsed as if no prototype was defined for them. In other words,
+Disable prototype checking.  With this option, all function calls are
+deparsed as if no prototype was defined for them.  In other words,
 
     perl -MO=Deparse,-P -e 'sub foo (\@) { 1 } foo @x'
 
@@ -4642,7 +4847,7 @@ making clear how the parameters are actually passed to C<foo>.
 =item B<-q>
 
 Expand double-quoted strings into the corresponding combinations of
-concatenation, uc, ucfirst, lc, lcfirst, quotemeta, and join. For
+concatenation, uc, ucfirst, lc, lcfirst, quotemeta, and join.  For
 instance, print
 
     print "Hello, $world, @ladies, \u$gentlemen\E, \u\L$me!";
@@ -4654,21 +4859,21 @@ as
 
 Note that the expanded form represents the way perl handles such
 constructions internally -- this option actually turns off the reverse
-translation that B::Deparse usually does. On the other hand, note that
+translation that B::Deparse usually does.  On the other hand, note that
 C<$x = "$y"> is not the same as C<$x = $y>: the former makes the value
 of $y into a string before doing the assignment.
 
 =item B<-s>I<LETTERS>
 
-Tweak the style of B::Deparse's output. The letters should follow
-directly after the 's', with no space or punctuation. The following
+Tweak the style of B::Deparse's output.  The letters should follow
+directly after the 's', with no space or punctuation.  The following
 options are available:
 
 =over 4
 
 =item B<C>
 
-Cuddle C<elsif>, C<else>, and C<continue> blocks. For example, print
+Cuddle C<elsif>, C<else>, and C<continue> blocks.  For example, print
 
     if (...) {
          ...
@@ -4689,11 +4894,11 @@ The default is not to cuddle.
 
 =item B<i>I<NUMBER>
 
-Indent lines by multiples of I<NUMBER> columns. The default is 4 columns.
+Indent lines by multiples of I<NUMBER> columns.  The default is 4 columns.
 
 =item B<T>
 
-Use tabs for each 8 columns of indent. The default is to use only spaces.
+Use tabs for each 8 columns of indent.  The default is to use only spaces.
 For instance, if the style options are B<-si4T>, a line that's indented
 3 times will be preceded by one tab and four spaces; if the options were
 B<-si8T>, the same line would be preceded by three tabs.
@@ -4702,14 +4907,14 @@ B<-si8T>, the same line would be preceded by three tabs.
 
 Print I<STRING> for the value of a constant that can't be determined
 because it was optimized away (mnemonic: this happens when a constant
-is used in B<v>oid context). The end of the string is marked by a period.
+is used in B<v>oid context).  The end of the string is marked by a period.
 The string should be a valid perl expression, generally a constant.
 Note that unless it's a number, it probably needs to be quoted, and on
-a command line quotes need to be protected from the shell. Some
+a command line quotes need to be protected from the shell.  Some
 conventional values include 0, 1, 42, '', 'foo', and
 'Useless use of constant omitted' (which may need to be
 B<-sv"'Useless use of constant omitted'.">
-or something similar depending on your shell). The default is '???'.
+or something similar depending on your shell).  The default is '???'.
 If you're using B::Deparse on a module or other file that's require'd,
 you shouldn't use a value that evaluates to false, since the customary
 true constant at the end of a module will be in void context when the
@@ -4720,8 +4925,8 @@ file is compiled as a main program.
 =item B<-x>I<LEVEL>
 
 Expand conventional syntax constructions into equivalent ones that expose
-their internal operation. I<LEVEL> should be a digit, with higher values
-meaning more expansion. As with B<-q>, this actually involves turning off
+their internal operation.  I<LEVEL> should be a digit, with higher values
+meaning more expansion.  As with B<-q>, this actually involves turning off
 special cases in B::Deparse's normal operations.
 
 If I<LEVEL> is at least 3, C<for> loops will be translated into equivalent
@@ -4802,7 +5007,7 @@ programs.
     $deparse = B::Deparse->new(OPTIONS)
 
 Create an object to store the state of a deparsing operation and any
-options. The options are the same as those that can be given on the
+options.  The options are the same as those that can be given on the
 command line (see L</OPTIONS>); options that are separated by commas
 after B<-MO=Deparse> should be given as separate strings.
 
@@ -4811,7 +5016,7 @@ after B<-MO=Deparse> should be given as separate strings.
     $deparse->ambient_pragmas(strict => 'all', '$[' => $[);
 
 The compilation of a subroutine can be affected by a few compiler
-directives, B<pragmas>. These are:
+directives, B<pragmas>.  These are:
 
 =over 4
 
@@ -4848,15 +5053,15 @@ use re;
 Ordinarily, if you use B::Deparse on a subroutine which has
 been compiled in the presence of one or more of these pragmas,
 the output will include statements to turn on the appropriate
-directives. So if you then compile the code returned by coderef2text,
+directives.  So if you then compile the code returned by coderef2text,
 it will behave the same way as the subroutine which you deparsed.
 
 However, you may know that you intend to use the results in a
-particular context, where some pragmas are already in scope. In
+particular context, where some pragmas are already in scope.  In
 this case, you use the B<ambient_pragmas> method to describe the
 assumptions you wish to make.
 
-Not all of the options currently have any useful effect. See
+Not all of the options currently have any useful effect.  See
 L</BUGS> for more details.
 
 The parameters it accepts are:
@@ -4866,7 +5071,7 @@ The parameters it accepts are:
 =item strict
 
 Takes a string, possibly containing several values separated
-by whitespace. The special values "all" and "none" mean what you'd
+by whitespace.  The special values "all" and "none" mean what you'd
 expect.
 
     $deparse->ambient_pragmas(strict => 'subs refs');
@@ -4888,7 +5093,7 @@ be in the ambient scope, otherwise not.
 =item re
 
 Takes a string, possibly containing a whitespace-separated list of
-values. The values "all" and "none" are special. It's also permissible
+values.  The values "all" and "none" are special.  It's also permissible
 to pass an array reference here.
 
     $deparser->ambient_pragmas(re => 'eval');
@@ -4897,14 +5102,14 @@ to pass an array reference here.
 =item warnings
 
 Takes a string, possibly containing a whitespace-separated list of
-values. The values "all" and "none" are special, again. It's also
+values.  The values "all" and "none" are special, again.  It's also
 permissible to pass an array reference here.
 
     $deparser->ambient_pragmas(warnings => [qw[void io]]);
 
 If one of the values is the string "FATAL", then all the warnings
 in that list will be considered fatal, just as with the B<warnings>
-pragma itself. Should you need to specify that some warnings are
+pragma itself.  Should you need to specify that some warnings are
 fatal, and others are merely enabled, you can pass the B<warnings>
 parameter twice:
 
@@ -4949,10 +5154,10 @@ stored in the special hash %^H.
 
 Return source code for the body of a subroutine (a block, optionally
 preceded by a prototype in parens), given a reference to the
-sub. Because a subroutine can have no names, or more than one name,
+sub.  Because a subroutine can have no names, or more than one name,
 this method doesn't return a complete subroutine definition -- if you
 want to eval the result, you should prepend "sub subname ", or "sub "
-for an anonymous function constructor. Unless the sub was defined in
+for an anonymous function constructor.  Unless the sub was defined in
 the main:: package, the code will include a package declaration.
 
 =head1 BUGS
@@ -4962,7 +5167,8 @@ the main:: package, the code will include a package declaration.
 =item *
 
 The only pragmas to be completely supported are: C<use warnings>,
-C<use strict 'refs'>, C<use bytes>, and C<use integer>. (C<$[>, which
+C<use strict>, C<use bytes>, C<use integer>
+and C<use feature>.  (C<$[>, which
 behaves like a pragma, is also supported.)
 
 Excepting those listed above, we're currently unable to guarantee that
@@ -4977,7 +5183,7 @@ than in the input file.
 
 In fact, the above is a specific instance of a more general problem:
 we can't guarantee to produce BEGIN blocks or C<use> declarations in
-exactly the right place. So if you use a module which affects compilation
+exactly the right place.  So if you use a module which affects compilation
 (such as by over-riding keywords, overloading constants or whatever)
 then the output code might not work as intended.
 
@@ -5003,7 +5209,8 @@ produced is already ordinary Perl which shouldn't be filtered again.
 
 =item *
 
-Optimised away statements are rendered as '???'. This includes statements that
+Optimised away statements are rendered as
+'???'.  This includes statements that
 have a compile-time side-effect, such as the obscure
 
     my $x if 0;
@@ -5017,7 +5224,7 @@ which is not, consequently, deparsed correctly.
 =item *
 
 Lexical (my) variables declared in scopes external to a subroutine
-appear in code2ref output text as package variables. This is a tricky
+appear in code2ref output text as package variables.  This is a tricky
 problem, as perl has no native facility for referring to a lexical variable
 defined within a different scope, although L<PadWalker> is a good start.