diff options
Diffstat (limited to 'systems/texlive/tlnet/tlpkg/tlperl/lib/B/Deparse.pm')
-rw-r--r-- | systems/texlive/tlnet/tlpkg/tlperl/lib/B/Deparse.pm | 418 |
1 files changed, 301 insertions, 117 deletions
diff --git a/systems/texlive/tlnet/tlpkg/tlperl/lib/B/Deparse.pm b/systems/texlive/tlnet/tlpkg/tlperl/lib/B/Deparse.pm index 67147f12dd..90a36752bd 100644 --- a/systems/texlive/tlnet/tlpkg/tlperl/lib/B/Deparse.pm +++ b/systems/texlive/tlnet/tlpkg/tlperl/lib/B/Deparse.pm @@ -7,13 +7,14 @@ # This is based on the module of the same name by Malcolm Beattie, # but essentially none of his code remains. -package B::Deparse; +package B::Deparse 1.74; +use strict; use Carp; use B qw(class main_root main_start main_cv svref_2object opnumber perlstring OPf_WANT OPf_WANT_VOID OPf_WANT_SCALAR OPf_WANT_LIST OPf_KIDS OPf_REF OPf_STACKED OPf_SPECIAL OPf_MOD OPf_PARENS OPpLVAL_INTRO OPpOUR_INTRO OPpENTERSUB_AMPER OPpSLICE OPpKVSLICE - OPpCONST_BARE + OPpCONST_BARE OPpEMPTYAVHV_IS_HV OPpTRANS_SQUASH OPpTRANS_DELETE OPpTRANS_COMPLEMENT OPpTARGET_MY OPpEXISTS_SUB OPpSORT_NUMERIC OPpSORT_INTEGER OPpREPEAT_DOLIST OPpSORT_REVERSE OPpMULTIDEREF_EXISTS OPpMULTIDEREF_DELETE @@ -21,13 +22,14 @@ use B qw(class main_root main_start main_cv svref_2object opnumber perlstring OPpPADHV_ISKEYS OPpRV2HV_ISKEYS OPpCONCAT_NESTED OPpMULTICONCAT_APPEND OPpMULTICONCAT_STRINGIFY OPpMULTICONCAT_FAKE - OPpTRUEBOOL OPpINDEX_BOOLNEG - SVf_IOK SVf_NOK SVf_ROK SVf_POK SVpad_OUR SVf_FAKE SVs_RMG SVs_SMG - SVs_PADTMP SVpad_TYPED - CVf_METHOD CVf_LVALUE + OPpTRUEBOOL OPpINDEX_BOOLNEG OPpDEFER_FINALLY + OPpARG_IF_UNDEF OPpARG_IF_FALSE + SVf_IOK SVf_NOK SVf_ROK SVf_POK SVf_FAKE SVs_RMG SVs_SMG + SVs_PADTMP + CVf_NOWARN_AMBIGUOUS CVf_LVALUE PMf_KEEP PMf_GLOBAL PMf_CONTINUE PMf_EVAL PMf_ONCE PMf_MULTILINE PMf_SINGLELINE PMf_FOLD PMf_EXTENDED PMf_EXTENDED_MORE - PADNAMEt_OUTER + PADNAMEf_OUTER PADNAMEf_OUR PADNAMEf_TYPED MDEREF_reload MDEREF_AV_pop_rv2av_aelem MDEREF_AV_gvsv_vivify_rv2av_aelem @@ -52,8 +54,6 @@ use B qw(class main_root main_start main_cv svref_2object opnumber perlstring MDEREF_SHIFT ); -$VERSION = '1.56'; -use strict; our $AUTOLOAD; use warnings (); require feature; @@ -272,7 +272,8 @@ BEGIN { BEGIN { for (qw[ const stringify rv2sv list glob pushmark null aelem kvaslice kvhslice padsv argcheck - nextstate dbstate rv2av rv2hv helem custom ]) { + nextstate dbstate rv2av rv2hv helem pushdefer leavetrycatch + custom ]) { eval "sub OP_\U$_ () { " . opnumber($_) . "}" }} @@ -447,14 +448,32 @@ sub next_todo { # emit the sub. my @text; my $flags = $name->FLAGS; - push @text, + my $category = !$cv || $seq <= $name->COP_SEQ_RANGE_LOW - ? $self->keyword($flags & SVpad_OUR + ? $self->keyword($flags & PADNAMEf_OUR ? "our" : $flags & SVpad_STATE ? "state" : "my") . " " : ""; + + # Skip lexical 'state' subs imported from the builtin:: + # package, since they are created automatically by + # use builtin "foo" + if ($cv && $category =~ /\bstate\b/) { + my $globname; + my $gv = $cv->GV; + if ( + $gv + && defined (($globname = $gv->object_2svref)) + && $$globname =~ /^\*builtin::/ + ) { + return ''; + } + } + + push @text, $category; + # XXX We would do $self->keyword("sub"), but ‘my CORE::sub’ # doesn’t work and ‘my sub’ ignores a &sub in scope. I.e., # we have a core bug here. @@ -822,16 +841,6 @@ sub new { return $self; } -{ - # 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; - } -} # Initialise the contextual information, either from # defaults provided with the ambient_pragmas method, @@ -839,9 +848,7 @@ sub new { sub init { my $self = shift; - $self->{'warnings'} = defined ($self->{'ambient_warnings'}) - ? $self->{'ambient_warnings'} & WARN_MASK - : undef; + $self->{'warnings'} = $self->{'ambient_warnings'}; $self->{'hints'} = $self->{'ambient_hints'}; $self->{'hinthash'} = $self->{'ambient_hinthash'}; @@ -1114,8 +1121,8 @@ sub pad_subs { if (defined $name && $name =~ /^&./) { my $low = $_->COP_SEQ_RANGE_LOW; my $flags = $_->FLAGS; - my $outer = $flags & PADNAMEt_OUTER; - if ($flags & SVpad_OUR) { + my $outer = $flags & PADNAMEf_OUTER; + if ($flags & PADNAMEf_OUR) { push @todo, [$low, undef, 0, $_] # [seq, no cv, not format, padname] unless $outer; @@ -1128,7 +1135,7 @@ sub pad_subs { my $flags = $flags; my $cv = $cv; my $name = $_; - while ($flags & PADNAMEt_OUTER && class ($protocv) ne 'CV') + while ($flags & PADNAMEf_OUTER && class ($protocv) ne 'CV') { $cv = $cv->OUTSIDE; next PADENTRY if class($cv) eq 'SPECIAL'; # XXX freed? @@ -1145,7 +1152,7 @@ sub pad_subs { my $other = $protocv->PADLIST; $$other && $other->outid == $padlist->id; }; - if ($flags & PADNAMEt_OUTER) { + if ($flags & PADNAMEf_OUTER) { next unless $defined_in_this_sub; push @todo, [$protocv->OUTSIDE_SEQ, $protocv, 0, $_]; next; @@ -1255,7 +1262,10 @@ sub deparse_argops { return unless $$kid and $kid->name eq 'argdefelem'; my $def = $self->deparse($kid->first, 7); $def = "($def)" if $kid->first->flags & OPf_PARENS; - $var .= " = $def"; + my $assign = "="; + $assign = "//=" if $kid->private & OPpARG_IF_UNDEF; + $assign = "||=" if $kid->private & OPpARG_IF_FALSE; + $var .= " $assign $def"; } push @sig, $var; } @@ -1306,7 +1316,7 @@ Carp::confess("NULL in deparse_sub") if !defined($cv) || $cv->isa("B::NULL"); Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL"); local $self->{'curcop'} = $self->{'curcop'}; - my $has_sig = $self->{hinthash}{feature_signatures}; + my $has_sig = $self->feature_enabled('signatures'); if ($cv->FLAGS & SVf_POK) { my $myproto = $cv->PV; if ($has_sig) { @@ -1316,9 +1326,9 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL"); $proto = $myproto; } } - if ($cv->CvFLAGS & (CVf_METHOD|CVf_LOCKED|CVf_LVALUE|CVf_ANONCONST)) { + if ($cv->CvFLAGS & (CVf_NOWARN_AMBIGUOUS|CVf_LOCKED|CVf_LVALUE|CVf_ANONCONST)) { push @attrs, "lvalue" if $cv->CvFLAGS & CVf_LVALUE; - push @attrs, "method" if $cv->CvFLAGS & CVf_METHOD; + push @attrs, "method" if $cv->CvFLAGS & CVf_NOWARN_AMBIGUOUS; push @attrs, "const" if $cv->CvFLAGS & CVf_ANONCONST; } @@ -1544,7 +1554,7 @@ sub maybe_parens_func { if ($prec <= $cx or substr($text, 0, 1) eq "(" or $self->{'parens'}) { return "$func($text)"; } else { - return "$func $text"; + return $func . (length($text) ? " $text" : ""); } } @@ -1554,7 +1564,7 @@ sub find_our_type { my $seq = $self->{'curcop'} ? $self->{'curcop'}->cop_seq : 0; for my $a (@{$self->{'curcvlex'}{"o$name"}}) { my ($st, undef, $padname) = @$a; - if ($st >= $seq && $padname->FLAGS & SVpad_TYPED) { + if ($st >= $seq && $padname->FLAGS & PADNAMEf_TYPED) { return $padname->SvSTASH->NAME; } } @@ -1640,7 +1650,7 @@ sub maybe_my { # because enteriter ops do not carry the flag. my $my = $self->keyword($padname->FLAGS & SVpad_STATE ? "state" : "my"); - if ($padname->FLAGS & SVpad_TYPED) { + if ($padname->FLAGS & PADNAMEf_TYPED) { $my .= ' ' . $padname->SvSTASH->NAME; } if ($need_parens) { @@ -1732,6 +1742,12 @@ sub scopeop { $body = $self->deparse($body, 1); return "$body $name $cond"; } + elsif($kid->type == OP_PUSHDEFER && + $kid->private & OPpDEFER_FINALLY && + $kid->sibling->type == OP_LEAVETRYCATCH && + null($kid->sibling->sibling)) { + return $self->pp_leavetrycatch_with_finally($kid->sibling, $kid, $cx); + } } else { $kid = $op->first; } @@ -1974,7 +1990,7 @@ sub populate_curcvlex { : ($ns[$i]->COP_SEQ_RANGE_LOW, $ns[$i]->COP_SEQ_RANGE_HIGH); push @{$self->{'curcvlex'}{ - ($ns[$i]->FLAGS & SVpad_OUR ? 'o' : 'm') . $name + ($ns[$i]->FLAGS & PADNAMEf_OUR ? 'o' : 'm') . $name }}, [$seq_st, $seq_en, $ns[$i]]; } } @@ -2075,7 +2091,7 @@ sub pragmata { my $warnings = $op->warnings; my $warning_bits; if ($warnings->isa("B::SPECIAL") && $$warnings == 4) { - $warning_bits = $warnings::Bits{"all"} & WARN_MASK; + $warning_bits = $warnings::Bits{"all"}; } elsif ($warnings->isa("B::SPECIAL") && $$warnings == 5) { $warning_bits = $warnings::NONE; @@ -2084,14 +2100,24 @@ sub pragmata { $warning_bits = undef; } else { - $warning_bits = $warnings->PV & WARN_MASK; + $warning_bits = $warnings->PV; } - if (defined ($warning_bits) and - !defined($self->{warnings}) || $self->{'warnings'} ne $warning_bits) { - push @text, - $self->declare_warnings($self->{'warnings'}, $warning_bits); - $self->{'warnings'} = $warning_bits; + my ($w1, $w2); + # The number of valid bit positions may have grown (by a byte or + # more) since the last warnings state, by custom warnings + # categories being registered in the meantime. Normalise the + # bitmasks first so they may be fairly compared. + $w1 = defined($self->{warnings}) + ? warnings::_expand_bits($self->{warnings}) + : undef; + $w2 = defined($warning_bits) + ? warnings::_expand_bits($warning_bits) + : undef; + + if (defined($w2) and !defined($w1) || $w1 ne $w2) { + push @text, $self->declare_warnings($w1, $w2); + $self->{'warnings'} = $w2; } my $hints = $op->hints; @@ -2176,13 +2202,13 @@ sub pp_nextstate { sub declare_warnings { my ($self, $from, $to) = @_; $from //= ''; - my $all = (warnings::bits("all") & WARN_MASK); - unless ((($from & WARN_MASK) & ~$all) =~ /[^\0]/) { + my $all = warnings::bits("all"); + unless (($from & ~$all) =~ /[^\0]/) { # no FATAL bits need turning off - if ( ($to & WARN_MASK) eq $all) { + if ( $to eq $all) { return $self->keyword("use") . " warnings;\n"; } - elsif (($to & WARN_MASK) eq ("\0"x length($to) & WARN_MASK)) { + elsif ($to eq ("\0"x length($to))) { return $self->keyword("no") . " warnings;\n"; } } @@ -2306,6 +2332,9 @@ my %feature_keywords = ( fc => 'fc', try => 'try', catch => 'try', + finally => 'try', + defer => 'defer', + signatures => 'signatures', ); # keywords that are strong and also have a prototype @@ -2489,7 +2518,21 @@ sub pp_chomp { maybe_targmy(@_, \&unop, "chomp") } sub pp_schop { maybe_targmy(@_, \&unop, "chop") } sub pp_schomp { maybe_targmy(@_, \&unop, "chomp") } sub pp_defined { unop(@_, "defined") } -sub pp_undef { unop(@_, "undef") } +sub pp_undef { + if ($_[1]->private & OPpTARGET_MY) { + my $targ = $_[1]->targ; + my $var = $_[0]->maybe_my($_[1], $_[2], $_[0]->padname($targ), + $_[0]->padname_sv($targ), + 1); + my $func = unop(@_, "undef"); + if ($func =~ /\s/) { + return unop(@_, "undef").$var; + } else { + return "$var = undef"; + } + } + unop(@_, "undef") +} sub pp_study { unop(@_, "study") } sub pp_ref { unop(@_, "ref") } sub pp_pos { maybe_local(@_, unop(@_, "pos")) } @@ -2747,19 +2790,40 @@ sub pp_anonlist { *pp_anonhash = \&pp_anonlist; +sub pp_emptyavhv { + my $self = shift; + my ($op, $cx, $forbid_parens) = @_; + my $val = ($op->private & OPpEMPTYAVHV_IS_HV) ? '{}' : '[]'; + if ($op->private & OPpTARGET_MY) { + my $targ = $op->targ; + my $var = $self->maybe_my($op, $cx, $self->padname($targ), + $self->padname_sv($targ), + $forbid_parens); + return $self->maybe_parens("$var = $val", $cx, 7); + } else { + return $val; + } +} + sub pp_refgen { my $self = shift; my($op, $cx) = @_; my $kid = $op->first; if ($kid->name eq "null") { my $anoncode = $kid = $kid->first; + + # Perl no longer generates this, but XS modules might: if ($anoncode->name eq "anonconst") { $anoncode = $anoncode->first->first->sibling; } + + # Same as with `anonconst`: if ($anoncode->name eq "anoncode" or !null($anoncode = $kid->sibling) and $anoncode->name eq "anoncode") { return $self->e_anoncode({ code => $self->padval($anoncode->targ) }); + + # Perl still generates this: } elsif ($kid->name eq "pushmark") { my $sib_name = $kid->sibling->name; if ($sib_name eq 'entersub') { @@ -2781,6 +2845,18 @@ sub e_anoncode { return $self->keyword("sub") . " $text"; } +sub pp_anoncode { + my ($self, $anoncode) = @_; + + return $self->e_anoncode( { code => $self->padval($anoncode->targ) } ); +} + +sub pp_anonconst { + my ($self, $anonconst) = @_; + + return $self->pp_anoncode( $anonconst->first->first->sibling ); +} + sub pp_srefgen { pp_refgen(@_) } sub pp_readline { @@ -3068,6 +3144,18 @@ sub pp_isa { binop(@_, "isa", 15) } sub pp_sassign { binop(@_, "=", 7, SWAP_CHILDREN) } sub pp_aassign { binop(@_, "=", 7, SWAP_CHILDREN | LIST_CONTEXT) } +sub pp_padsv_store { + my $self = shift; + my ($op, $cx, $forbid_parens, @args) = @_; + my $targ = $op->targ; + my $var = $self->maybe_my($op, $cx, $self->padname($targ), + $self->padname_sv($targ), + $forbid_parens); + + my $val = $self->deparse($op->first, 7); + return $self->maybe_parens("$var = $val", $cx, 7); +} + sub pp_smartmatch { my ($self, $op, $cx) = @_; if (($op->flags & OPf_SPECIAL) && $self->{expand} < 2) { @@ -3669,7 +3757,7 @@ sub maybe_var_attr { return unless $loppriv & OPpLVAL_INTRO; my $padname = $self->padname_sv($lop->targ); - my $thisclass = ($padname->FLAGS & SVpad_TYPED) + my $thisclass = ($padname->FLAGS & PADNAMEf_TYPED) ? $padname->SvSTASH->NAME : 'main'; # all pad vars must be in the same class @@ -3788,9 +3876,12 @@ sub pp_list { $local = "my"; } my $padname = $self->padname_sv($lop->targ); - if ($padname->FLAGS & SVpad_TYPED) { + if ($padname->FLAGS & PADNAMEf_TYPED) { $newtype = $padname->SvSTASH->NAME; } + } elsif ($lopname eq 'padsv_store') { + # don't interpret as my (list) if it has an implicit assign + $local = ""; } elsif ($lopname =~ /^(?:gv|rv2)([ash])v$/ && $loppriv & OPpOUR_INTRO or $lopname eq "null" && class($lop) eq 'UNOP' @@ -3953,7 +4044,21 @@ sub loop_common { } else { $ary = $self->deparse($ary, 1); } - if (null $var) { + + if ($enter->flags & OPf_PARENS) { + # for my ($x, $y, ...) ... + # for my ($foo, $bar) () stores the count (less 1) in the targ of + # the ITER op. For the degenerate case of 1 var ($x), the + # TARG is zero, so it works anyway + my $iter_targ = $kid->first->first->targ; + my @vars; + my $targ = $enter->targ; + while ($iter_targ-- >= 0) { + push @vars, $self->padname_sv($targ)->PVX; + ++$targ; + } + $var = 'my (' . join(', ', @vars) . ')'; + } elsif (null $var) { $var = $self->pp_padsv($enter, 1, 1); } elsif ($var->name eq "rv2gv") { $var = $self->pp_rv2sv($var, 1); @@ -4057,9 +4162,9 @@ sub pp_leavetry { return "eval {\n\t" . $self->pp_leave(@_) . "\n\b}"; } -sub pp_leavetrycatch { +sub pp_leavetrycatch_with_finally { my $self = shift; - my ($op) = @_; + my ($op, $finallyop) = @_; # Expect that the first three kids should be (entertrycatch, poptry, catch) my $entertrycatch = $op->first; @@ -4072,14 +4177,30 @@ sub pp_leavetrycatch { $catch->name eq "catch" or die "Expected catch as third child of leavetrycatch"; my $catchblock = $catch->first->sibling; - $catchblock->name eq "scope" or die "Expected scope as second child of catch"; + my $name = $catchblock->name; + unless ($name eq "scope" || $name eq "leave") { + die "Expected scope or leave as second child of catch, got $name instead"; + } my $trycode = scopeop(0, $self, $tryblock); my $catchvar = $self->padname($catch->targ); - my $catchcode = scopeop(0, $self, $catchblock); + my $catchcode = $name eq 'scope' ? scopeop(0, $self, $catchblock) + : scopeop(1, $self, $catchblock); + + my $finallycode = ""; + if($finallyop) { + my $body = $self->deparse($finallyop->first->first); + $finallycode = "\nfinally {\n\t$body\n\b}"; + } return "try {\n\t$trycode\n\b}\n" . - "catch($catchvar) {\n\t$catchcode\n\b}\cK"; + "catch($catchvar) {\n\t$catchcode\n\b}$finallycode\cK"; +} + +sub pp_leavetrycatch { + my $self = shift; + my ($op, @args) = @_; + return $self->pp_leavetrycatch_with_finally($op, undef, @args); } sub _op_is_or_was { @@ -4225,6 +4346,17 @@ sub pp_gv { return $self->maybe_qualify("", $self->gv_name($gv)); } +sub pp_aelemfastlex_store { + my $self = shift; + my($op, $cx) = @_; + my $name = $self->padname($op->targ); + $name =~ s/^@/\$/; + my $i = $op->private; + $i -= 256 if $i > 127; + my $val = $self->deparse($op->first, 7); + return $self->maybe_parens("${name}[$i] = $val", $cx, 7); +} + sub pp_aelemfast_lex { my $self = shift; my($op, $cx) = @_; @@ -4922,78 +5054,92 @@ sub e_method { sub check_proto { my $self = shift; return "&" if $self->{'noproto'}; - my($proto, @args) = @_; - my($arg, $real); + my ($proto, @args) = @_; my $doneok = 0; my @reals; - # An unbackslashed @ or % gobbles up the rest of the args - 1 while $proto =~ s/(?<!\\)([@%])[^\]]+$/$1/; - $proto =~ s/^\s*//; - while ($proto) { - $proto =~ s/^(\\?[\$\@&%*_]|\\\[[\$\@&%*]+\]|;|)\s*//; + $proto =~ s/^\s+//; + while (length $proto) { + $proto =~ s/^(\\?[\$\@&%*]|\\\[[\$\@&%*]+\]|[_+;])\s*// + or return "&"; # malformed prototype my $chr = $1; - if ($chr eq "") { - return "&" if @args; - } elsif ($chr eq ";") { + if ($chr eq ";") { $doneok = 1; - } elsif ($chr eq "@" or $chr eq "%") { + } elsif ($chr eq '@' or $chr eq '%') { + # An unbackslashed @ or % gobbles up the rest of the args push @reals, map($self->deparse($_, 6), @args); @args = (); + $proto = ''; + } elsif (!@args) { + last if $doneok; + return "&"; # too few args and no ';' } else { - $arg = shift @args; - last unless $arg; - if ($chr eq "\$" || $chr eq "_") { + my $arg = shift @args; + if ($chr eq '$' || $chr eq '_') { if (want_scalar $arg) { push @reals, $self->deparse($arg, 6); } else { return "&"; } } elsif ($chr eq "&") { - if ($arg->name =~ /^(s?refgen|undef)$/) { + if ($arg->name =~ /^(?:s?refgen|undef)\z/) { push @reals, $self->deparse($arg, 6); } else { return "&"; } } elsif ($chr eq "*") { - if ($arg->name =~ /^s?refgen$/ + if ($arg->name =~ /^s?refgen\z/ and $arg->first->first->name eq "rv2gv") - { - $real = $arg->first->first; # skip refgen, null - if ($real->first->name eq "gv") { - push @reals, $self->deparse($real, 6); - } else { - push @reals, $self->deparse($real->first, 6); - } - } else { - return "&"; - } + { + my $real = $arg->first->first; # skip refgen, null + if ($real->first->name eq "gv") { + push @reals, $self->deparse($real, 6); + } else { + push @reals, $self->deparse($real->first, 6); + } + } else { + return "&"; + } + } elsif ($chr eq "+") { + my $real; + if ($arg->name =~ /^s?refgen\z/ and + !null($real = $arg->first) and + !null($real->first) and + $real->first->name =~ /^(?:rv2|pad)[ah]v\z/) + { + push @reals, $self->deparse($real, 6); + } elsif (want_scalar $arg) { + push @reals, $self->deparse($arg, 6); + } else { + return "&"; + } } elsif (substr($chr, 0, 1) eq "\\") { $chr =~ tr/\\[]//d; - if ($arg->name =~ /^s?refgen$/ and + my $real; + if ($arg->name =~ /^s?refgen\z/ and !null($real = $arg->first) and ($chr =~ /\$/ && is_scalar($real->first) or ($chr =~ /@/ - && class($real->first->sibling) ne 'NULL' - && $real->first->sibling->name - =~ /^(rv2|pad)av$/) + && !null($real->first) + && $real->first->name =~ /^(?:rv2|pad)av\z/) or ($chr =~ /%/ - && class($real->first->sibling) ne 'NULL' - && $real->first->sibling->name - =~ /^(rv2|pad)hv$/) + && !null($real->first) + && $real->first->name =~ /^(?:rv2|pad)hv\z/) #or ($chr =~ /&/ # This doesn't work # && $real->first->name eq "rv2cv") or ($chr =~ /\*/ && $real->first->name eq "rv2gv"))) - { - push @reals, $self->deparse($real, 6); - } else { - return "&"; - } - } - } + { + push @reals, $self->deparse($real, 6); + } else { + return "&"; + } + } else { + # should not happen + return "&"; + } + } } - return "&" if $proto and !$doneok; # too few args and no ';' - return "&" if @args; # too many args + return "&" if @args; # too many args return ("", join ", ", @reals); } @@ -5038,7 +5184,7 @@ sub retscalar { |msgrcv|semop|semget|semctl|hintseval|shostent|snetent |sprotoent|sservent|ehostent|enetent|eprotoent|eservent |spwent|epwent|sgrent|egrent|getlogin|syscall|lock|runcv - |fc)\z/x + |fc|padsv_store)\z/x } sub pp_entersub { @@ -5049,9 +5195,7 @@ sub pp_entersub { my $prefix = ""; my $amper = ""; my($kid, @exprs); - if ($op->flags & OPf_SPECIAL && !($op->flags & OPf_MOD)) { - $prefix = "do "; - } elsif ($op->private & OPpENTERSUB_AMPER) { + if ($op->private & OPpENTERSUB_AMPER) { $amper = "&"; } $kid = $op->first; @@ -5175,19 +5319,23 @@ sub pp_entersub { # it back. $kid =~ s/^CORE::GLOBAL:://; - my $dproto = defined($proto) ? $proto : "undefined"; - my $scalar_proto = $dproto =~ /^;*(?:[\$*_+]|\\.|\\\[[^]]\])\z/; if (!$declared) { return "$kid(" . $args . ")"; - } elsif ($dproto =~ /^\s*\z/) { + } + + my $dproto = defined($proto) ? $proto : "undefined"; + if ($dproto =~ /^\s*\z/) { return $kid; - } elsif ($scalar_proto and is_scalar($exprs[0])) { + } + + my $scalar_proto = $dproto =~ /^ \s* (?: ;\s* )* (?: [\$*_+] |\\ \s* (?: [\$\@%&*] | \[ [^\]]+ \] ) ) \s* \z/x; + if ($scalar_proto and !@exprs || is_scalar($exprs[0])) { # is_scalar is an excessively conservative test here: # really, we should be comparing to the precedence of the # top operator of $exprs[0] (ala unop()), but that would # take some major code restructuring to do right. return $self->maybe_parens_func($kid, $args, $cx, 16); - } elsif (not $scalar_proto and defined($proto) || $simple) { #' + } elsif (not $scalar_proto and defined($proto) || $simple) { return $self->maybe_parens_func($kid, $args, $cx, 5); } else { return "$kid(" . $args . ")"; @@ -5295,7 +5443,7 @@ sub re_unback { # the insane complexity here is due to the behaviour of "\c\" $str =~ s/ # these two lines ensure that the backslash we're about to - # remove isn't preceeded by something which makes it part + # remove isn't preceded by something which makes it part # of a \c (^ | [^\\] | \\c\\) # $1 @@ -5408,9 +5556,15 @@ sub const { return $self->const_dumper($sv, $cx); } if (class($sv) eq "SPECIAL") { - # sv_undef, sv_yes, sv_no - return $$sv == 3 ? $self->maybe_parens("!1", $cx, 21) - : ('undef', '1')[$$sv-1]; + # PL_sv_undef etc + # return yes/no as boolean expressions rather than integers to + # preserve their boolean-ness + return + $$sv == 1 ? 'undef' : # PL_sv_undef + $$sv == 2 ? $self->maybe_parens("!0", $cx, 21) : # PL_sv_yes + $$sv == 3 ? $self->maybe_parens("!1", $cx, 21) : # PL_sv_no + $$sv == 7 ? '0' : # PL_sv_zero + '"???"'; } if (class($sv) eq "NULL") { return 'undef'; @@ -5431,10 +5585,10 @@ sub const { if ($nv == 0) { if (pack("F", $nv) eq pack("F", 0)) { # positive zero - return "0"; + return "0.0"; } else { # negative zero - return $self->maybe_parens("-.0", $cx, 21); + return $self->maybe_parens("-0.0", $cx, 21); } } elsif (1/$nv == 0) { if ($nv > 0) { @@ -5471,6 +5625,10 @@ sub const { return $self->maybe_parens("$mant * 2**$exp", $cx, 19); } } + + # preserve NV-ness: output as NNN.0 rather than NNN + $str .= ".0" if $str =~ /^-?[0-9]+$/; + $str = $self->maybe_parens($str, $cx, 21) if $nv < 0; return $str; } elsif ($sv->FLAGS & SVf_ROK && $sv->can("RV")) { @@ -6252,9 +6410,7 @@ sub matchop { ->sibling # entersub ->first # ex-list ->first # pushmark - ->sibling # srefgen - ->first # ex-list - ->first # anoncode + ->sibling # anoncode ->targ ) : undef); @@ -6578,6 +6734,34 @@ sub pp_argdefelem { } +sub pp_pushdefer { + my $self = shift; + my($op, $cx) = @_; + # defer block body is stored in the ->first of an OP_NULL that is + # ->first of OP_PUSHDEFER + my $body = $self->deparse($op->first->first); + return "defer {\n\t$body\n\b}\cK"; +} + +sub builtin1 { + my $self = shift; + my ($op, $cx, $name) = @_; + my $arg = $self->deparse($op->first); + # TODO: work out if lexical alias is present somehow... + return "builtin::$name($arg)"; +} + +sub pp_is_bool { builtin1(@_, "is_bool"); } +sub pp_is_weak { builtin1(@_, "is_weak"); } +sub pp_weaken { builtin1(@_, "weaken"); } +sub pp_unweaken { builtin1(@_, "unweaken"); } +sub pp_blessed { builtin1(@_, "blessed"); } +sub pp_refaddr { $_[0]->maybe_targmy(@_[1,2], \&builtin1, "refaddr"); } +sub pp_reftype { $_[0]->maybe_targmy(@_[1,2], \&builtin1, "reftype"); } +sub pp_ceil { $_[0]->maybe_targmy(@_[1,2], \&builtin1, "ceil"); } +sub pp_floor { $_[0]->maybe_targmy(@_[1,2], \&builtin1, "floor"); } +sub pp_is_tainted { builtin1(@_, "is_tainted"); } + 1; __END__ |