($] < 5.008009 ? () : qw(OPpCONST_NOVER OPpPAD_STATE)),
($] < 5.009 ? 'PMf_SKIPWHITE' : qw(RXf_SKIPWHITE)),
($] < 5.011 ? 'CVf_LOCKED' : 'OPpREVERSE_INPLACE'),
- ($] < 5.013 ? () : 'PMf_NONDESTRUCT');
-$VERSION = "1.08";
+ ($] < 5.013 ? () : 'PMf_NONDESTRUCT'),
+ ($] < 5.015003 ? qw(OPpCONST_ARYBASE) : ()),
+ ($] < 5.015005 ? () : qw(OPpEVAL_BYTES));
+$VERSION = "1.09";
use strict;
use vars qw/$AUTOLOAD/;
use warnings ();
# 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 RXf_SKIPWHITE CVf_LOCKED OPpREVERSE_INPLACE
- PMf_NONDESTRUCT)) {
+ PMf_NONDESTRUCT OPpCONST_ARYBASE OPpEVAL_BYTES)) {
no strict 'refs';
*{$_} = sub () {0} unless *{$_}{CODE};
}
$self->{'use_dumper'} = 0;
$self->{'use_tabs'} = 0;
+ $self->{'ambient_arybase'} = 0;
$self->{'ambient_warnings'} = undef; # Assume no lexical warnings
$self->{'ambient_hints'} = 0;
$self->{'ambient_hinthash'} = undef;
sub init {
my $self = shift;
+ $self->{'arybase'} = $self->{'ambient_arybase'};
$self->{'warnings'} = defined ($self->{'ambient_warnings'})
? $self->{'ambient_warnings'} & WARN_MASK
: undef;
sub ambient_pragmas {
my $self = shift;
- my ($hint_bits, $warning_bits, $hinthash) = (0);
+ my ($arybase, $hint_bits, $warning_bits, $hinthash) = (0, 0);
while (@_ > 1) {
my $name = shift();
$hint_bits |= strict::bits(@names);
}
+ elsif ($name eq '$[') {
+ if (OPpCONST_ARYBASE) {
+ $arybase = $val;
+ } else {
+ croak "\$[ can't be non-zero on this perl" unless $val == 0;
+ }
+ }
+
elsif ($name eq 'integer'
|| $name eq 'bytes'
|| $name eq 'utf8') {
croak "The ambient_pragmas method expects an even number of args";
}
+ $self->{'ambient_arybase'} = $arybase;
$self->{'ambient_warnings'} = $warning_bits;
$self->{'ambient_hints'} = $hint_bits;
$self->{'ambient_hinthash'} = $hinthash;
return "$prefix$name";
}
- if (defined $cx && $cx == 26) {
- if ($prefix eq '@' && $name =~ /^[^\w+-]$/) {
+ if ($name =~ /^[^\w+-]$/) {
+ if (defined $cx && $cx == 26) {
+ if ($prefix eq '@') {
return "$prefix\{$name}";
}
+ elsif ($name eq '#') { return '${#}' } # "${#}a" vs "$#a"
+ }
+ if ($prefix eq '$#') {
+ return "\$#{$name}";
+ }
}
my $v = ($prefix eq '$#' ? '@' : $prefix) . $name;
}
# Notice how subs and formats are inserted between statements here;
-# also pragmas.
+# also $[ assignments and pragmas.
sub pp_nextstate {
my $self = shift;
my($op, $cx) = @_;
$self->{'curstash'} = $stash;
}
+ if (OPpCONST_ARYBASE && $self->{'arybase'} != $op->arybase) {
+ push @text, '$[ = '. $op->arybase .";\n";
+ $self->{'arybase'} = $op->arybase;
+ }
+
my $warnings = $op->warnings;
my $warning_bits;
if ($warnings->isa("B::SPECIAL") && $$warnings == 4) {
when => 'switch',
default => 'switch',
break => 'switch',
+ evalbytes=>'evalbytes',
);
sub keyword {
my $name = shift;
return $name if $name =~ /^CORE::/; # just in case
if (exists $feature_keywords{$name}) {
- return
- $self->{'hinthash'}
- && $self->{'hinthash'}{"feature_$feature_keywords{$name}"}
- ? $name
- : "CORE::$name";
+ return "CORE::$name"
+ if !$self->{'hinthash'}
+ || !$self->{'hinthash'}{"feature_$feature_keywords{$name}"}
}
if (
- $name !~ /^(?:chom?p|exec|s(?:elect|ystem))\z/
+ $name !~ /^(?:chom?p|do|exec|glob|s(?:elect|ystem))\z/
&& !defined eval{prototype "CORE::$name"}
) { return $name }
if (
sub pp_sleep { maybe_targmy(@_, \&unop, "sleep") }
sub pp_dofile { unop(@_, "do") }
-sub pp_entereval { unop(@_, "eval") }
+sub pp_entereval {
+ unop(
+ @_,
+ $_[1]->private & OPpEVAL_BYTES ? $_[0]->keyword('evalbytes') : "eval"
+ )
+}
sub pp_ghbyname { unop(@_, "gethostbyname") }
sub pp_gnbyname { unop(@_, "getnetbyname") }
my $self = shift;
my($op, $cx) = @_;
my $text = $self->dq($op->first->sibling); # skip pushmark
+ my $keyword =
+ $op->flags & OPf_SPECIAL ? 'glob' : $self->keyword('glob');
if ($text =~ /^\$?(\w|::|\`)+$/ # could look like a readline
- or $text =~ /[<>]/) {
- return 'glob(' . single_delim('qq', '"', $text) . ')';
+ or $keyword =~ /^CORE::/
+ or $text =~ /[<>]/) {
+ return "$keyword(" . single_delim('qq', '"', $text) . ')';
} else {
return '<' . $text . '>';
}
my($op, $cx) = @_;
my($expr, @exprs);
my $kid = $op->first->sibling; # skip pushmark
+ return '' if class($kid) eq 'NULL';
my $lop;
my $local = "either"; # could be local(...), my(...), state(...) or our(...)
for ($lop = $kid; !null($lop); $lop = $lop->sibling) {
my($op, $cx) = @_;
my $name = $self->padname($op->targ);
$name =~ s/^@/\$/;
- return $name . "[" . $op->private . "]";
+ return $name . "[" . ($op->private + $self->{'arybase'}) . "]";
}
sub pp_aelemfast {
$name = $self->{'curstash'}."::$name"
if $name !~ /::/ && $self->lex_in_scope('@'.$name);
$name = '$' . $name;
- return $name . "[" . $op->private . "]";
+ return $name . "[" . ($op->private + $self->{'arybase'}) . "]";
}
sub rv2x {
sub pp_const {
my $self = shift;
my($op, $cx) = @_;
+ if ($op->private & OPpCONST_ARYBASE) {
+ return '$[';
+ }
# if ($op->private & OPpCONST_BARE) { # trouble with `=>' autoquoting
# return $self->const_sv($op)->PV;
# }
my $op = shift;
my $type = $op->name;
if ($type eq "const") {
+ return '$[' if $op->private & OPpCONST_ARYBASE;
return uninterp(escape_str(unback($self->const_sv($op)->as_string)));
} elsif ($type eq "concat") {
my $first = $self->dq($op->first);
my $type = $op->name;
if ($type eq "const") {
+ return '$[' if $op->private & OPpCONST_ARYBASE;
my $unbacked = re_unback($self->const_sv($op)->as_string);
return re_uninterp_extended(escape_extended_re($unbacked))
if $extended;
=head2 ambient_pragmas
- $deparse->ambient_pragmas(strict => 'all');
+ $deparse->ambient_pragmas(strict => 'all', '$[' => $[);
The compilation of a subroutine can be affected by a few compiler
directives, B<pragmas>. These are:
=item *
+Assigning to the special variable $[
+
+=item *
+
use integer;
=item *
$deparse->ambient_pragmas(strict => 'subs refs');
+=item $[
+
+Takes a number, the value of the array base $[.
+Cannot be non-zero on Perl 5.15.3 or later.
+
=item bytes
=item utf8
$deparser->ambient_pragmas (
hint_bits => $hint_bits,
warning_bits => $warning_bits,
+ '$[' => 0 + $[
); }
which specifies that the ambient pragmas are exactly those which
=item *
The only pragmas to be completely supported are: C<use warnings>,
-C<use strict 'refs'>, C<use bytes>, and C<use integer>.
+C<use strict 'refs'>, C<use bytes>, and C<use integer>. (C<$[>, which
+behaves like a pragma, is also supported.)
Excepting those listed above, we're currently unable to guarantee that
B::Deparse will produce a pragma at the correct point in the program.