99
1010package B::Deparse 1.88;
1111use strict;
12+ use builtin qw( true false ) ;
1213use Carp;
1314use B qw( class main_root main_start main_cv svref_2object opnumber perlstring
1415 OPf_WANT OPf_WANT_VOID OPf_WANT_SCALAR OPf_WANT_LIST
@@ -1192,11 +1193,14 @@ sub pad_subs {
11921193
11931194
11941195# deparse_multiparam(): deparse, if possible, a sequence of ops into a
1195- # subroutine signature. If possible, returns a string representing the
1196- # signature syntax, minus the surrounding parentheses.
1196+ # subroutine signature. If possible, returns either:
1197+ # (if $use_feature_sig is true): a string representing the signature syntax,
1198+ # minus the surrounding parentheses.
1199+ # (if $use_feature_sig is false): a string of perl code that approximates
1200+ # the behaviour of the signature.
11971201
11981202sub deparse_multiparam {
1199- my ($self , $topop , $cv ) = @_ ;
1203+ my ($self , $topop , $cv , $use_feature_sig ) = @_ ;
12001204
12011205 $topop = $topop -> first;
12021206 return unless $$topop and $topop -> name eq ' lineseq' ;
@@ -1223,16 +1227,20 @@ sub deparse_multiparam {
12231227 my @param_padix = splice @rest , 0, $nparams , ();
12241228 my ($slurpy_padix ) = @rest ;
12251229
1226- my @sig ;
1230+ my @param_padname = map { $_ ? $self -> padname($_ ) : ' $' } @param_padix ;
1231+ my ($slurpy_padname ) = map { $_ ? $self -> padname($_ ) : $slurpy } $slurpy_padix ;
1232+
12271233 my %parami_for_padix ;
12281234
12291235 # Initial scalars
12301236 foreach my $parami ( 0 .. $max_args -1 ) {
12311237 my $padix = $param_padix [$parami ];
1232- $sig [$parami ] = $self -> padname($padix ) || ' $' ;
12331238 $parami_for_padix {$padix } = $parami ;
12341239 }
12351240
1241+ my @param_defmode ;
1242+ my @param_defexpr ;
1243+
12361244 $o = $o -> sibling;
12371245 for (; $o and !null $o ; $o = $o -> sibling) {
12381246 # Look for OP_NULL[OP_PARAMTEST[OP_PARAMSTORE]]
@@ -1244,39 +1252,100 @@ sub deparse_multiparam {
12441252
12451253 my $parami = $parami_for_padix {$ofirst -> targ};
12461254
1247- my $assign = " =" ;
1248- $assign = " //=" if $ofirst -> private == OPpPARAM_IF_UNDEF;
1249- $assign = " ||=" if $ofirst -> private == OPpPARAM_IF_FALSE;
1250-
1251- length $sig [$parami ] > 1 ?
1252- ( $sig [$parami ] .= ' ' ) :
1253- ( $sig [$parami ] = ' $' ); # intentionally no trailing space
1255+ my $defmode = " =" ;
1256+ $defmode = " //=" if $ofirst -> private == OPpPARAM_IF_UNDEF;
1257+ $defmode = " ||=" if $ofirst -> private == OPpPARAM_IF_FALSE;
1258+ $param_defmode [$parami ] = $defmode ;
12541259
12551260 my $defop = $ofirst -> first-> first;
1256- if ($defop -> name eq " stub" ) {
1257- $sig [$parami ] .= " $assign " ;
1258- }
1259- else {
1260- my $def = $self -> deparse($defop , 7);
1261- $def = " ($def )" if $defop -> flags & OPf_PARENS;
1261+ if ($defop -> name ne " stub" ) {
1262+ my $expr = $self -> deparse($defop , 7);
1263+ $expr = " ($expr )" if $defop -> flags & OPf_PARENS;
12621264
1263- $sig [$parami ] .= " $assign $def " ;
1265+ $param_defexpr [$parami ] = $expr ;
12641266 }
12651267 }
12661268 }
12671269
12681270 if ($cv -> CvFLAGS & CVf_IsMETHOD) {
12691271 # Remove the implied `$self` argument
12701272 warn " Expected first signature argument to be named \$ self"
1271- unless @sig and $sig [0] eq ' $self' ;
1272- shift @sig ;
1273+ unless @param_padname and $param_padname [0] eq ' $self' ;
1274+
1275+ shift @param_padix ;
1276+ shift @param_padname ;
1277+ shift @param_defmode ;
1278+ shift @param_defexpr ;
1279+ }
1280+
1281+ if ($use_feature_sig ) {
1282+ my @sig ;
1283+
1284+ foreach my $parami ( 0 .. $#param_padix ) {
1285+ my $param_sig = $param_padname [$parami ];
1286+ if ($param_defmode [$parami ]) {
1287+ length $param_sig > 1 ?
1288+ ( $param_sig .= ' ' ) :
1289+ ( $param_sig = ' $' ); # intentionally no trailing space
1290+
1291+ $param_sig .= $param_defmode [$parami ];
1292+
1293+ my $defexpr = $param_defexpr [$parami ];
1294+ $param_sig .= " $defexpr " if defined $defexpr ;
1295+ }
1296+
1297+ push @sig , $param_sig ;
1298+ }
1299+
1300+ push @sig , $slurpy_padname if $slurpy ;
1301+
1302+ return join (" , " , @sig );
1303+ }
1304+
1305+ # Approximate the behaviour using plain perl code
1306+ my $code = " " ;
1307+
1308+ $code .= <<"EOF" if !$slurpy_padix ;
1309+ die sprintf("Too many arguments for subroutine at %s line %d .\\ n", (caller)[1, 2]) unless \@ _ <= $nparams ;
1310+ EOF
1311+
1312+ $code .= <<"EOF" if $min_args > 0;
1313+ die sprintf("Too few arguments for subroutine at %s line %d .\\ n", (caller)[1, 2]) unless \@ _ >= $min_args ;
1314+ EOF
1315+
1316+ $code .= <<EOF if $slurpy and $slurpy eq ' %' ;
1317+ die sprintf("Odd name/value argument for subroutine at %s line %d .\\ n", (caller)[1, 2]) if \@ _ > $nparams && ((\@ _ - $nparams ) & 1);
1318+ EOF
1319+
1320+ foreach my $parami ( 0 .. $#param_padix ) {
1321+ my $argix = $parami ;
1322+
1323+ $code .= " my $param_padname [$parami ] = " ;
1324+
1325+ if (my $defmode = $param_defmode [$parami ]) {
1326+ my $defexpr = $param_defexpr [$parami ];
1327+
1328+ if ($defmode eq " =" ) {
1329+ $code .= " \@ _ > $argix ? \$ _[$argix ] : $defexpr " ;
1330+ }
1331+ else {
1332+ $defmode =~ s / =\z // ;
1333+ $code .= " \$ _[$argix ] $defmode $defexpr " ;
1334+ }
1335+ }
1336+ else {
1337+ $code .= " \$ _[$argix ]" ;
1338+ }
1339+
1340+ $code .= " ;\n " ;
12731341 }
12741342
12751343 if ($slurpy ) {
1276- push @sig , $slurpy_padix ? $self -> padname( $slurpy_padix ) : $slurpy ;
1344+ $code .= " my $slurpy_padname = \@ _[ $nparams .. \$ #_]; \n " ;
12771345 }
12781346
1279- return join (" , " , @sig );
1347+ $code =~ s / ;\n\z // ;
1348+ return $code ;
12801349}
12811350
12821351# deparse_argops(): deparse, if possible, a sequence of argcheck + argelem
@@ -1434,10 +1503,10 @@ Carp::confess("NULL in deparse_sub") if !defined($cv) || $cv->isa("B::NULL");
14341503Carp::confess(" SPECIAL in deparse_sub" ) if $cv -> isa(" B::SPECIAL" );
14351504 local $self -> {' curcop' } = $self -> {' curcop' };
14361505
1437- my $has_sig = $self -> feature_enabled(' signatures' );
1506+ my $use_feature_sig = $self -> feature_enabled(' signatures' );
14381507 if ($cv -> FLAGS & SVf_POK) {
14391508 my $myproto = $cv -> PV;
1440- if ($has_sig ) {
1509+ if ($use_feature_sig ) {
14411510 push @attrs , " prototype($myproto )" ;
14421511 }
14431512 else {
@@ -1457,7 +1526,7 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
14571526 local ($self -> {' curcvlex' });
14581527 local (@$self {qw' curstash warnings hints hinthash' })
14591528 = @$self {qw' curstash warnings hints hinthash' };
1460- my $body ;
1529+ my $body = " " ;
14611530 my $root = $cv -> ROOT;
14621531 local $B::overlay = {};
14631532 if (not null $root ) {
@@ -1471,16 +1540,21 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
14711540
14721541 # Try to deparse first subtree as a signature if possible.
14731542 # Top of signature subtree has an ex-argcheck as a placeholder
1474- if ( $has_sig
1475- and $$firstop
1476- and $firstop -> name eq ' null'
1477- and $firstop -> targ == OP_ARGCHECK
1478- ) {
1479- my ($mysig ) = $self -> deparse_multiparam($firstop , $cv ) //
1480- $self -> deparse_argops($firstop , $cv );
1481- if (defined $mysig ) {
1482- $sig = $mysig ;
1483- $firstop = $is_list ? $firstop -> sibling : undef ;
1543+ if ($$firstop and $firstop -> name eq ' null' and $firstop -> targ == OP_ARGCHECK) {
1544+ if ($use_feature_sig ) {
1545+ my ($mysig ) = $self -> deparse_multiparam($firstop , $cv , true) //
1546+ $self -> deparse_argops($firstop , $cv );
1547+ if (defined $mysig ) {
1548+ $sig = $mysig ;
1549+ $firstop = $is_list ? $firstop -> sibling : undef ;
1550+ }
1551+ }
1552+ else {
1553+ my $prelude = $self -> deparse_multiparam($firstop , $cv , false);
1554+ if (defined $prelude ) {
1555+ $body .= $prelude ;
1556+ $firstop = $is_list ? $firstop -> sibling : undef ;
1557+ }
14841558 }
14851559 }
14861560
@@ -1489,8 +1563,8 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
14891563 for (my $o = $firstop ; $$o ; $o =$o -> sibling) {
14901564 push @ops , $o ;
14911565 }
1492- $body = $self -> lineseq(undef , 0, @ops )." ;" ;
1493- if (!$has_sig and $ops [-1]-> name =~ / ^(next|db)state$ / ) {
1566+ $body . = $self -> lineseq(undef , 0, @ops )." ;" ;
1567+ if (!$use_feature_sig and $ops [-1]-> name =~ / ^(next|db)state$ / ) {
14941568 # this handles void context in
14951569 # use feature signatures; sub ($=1) {}
14961570 $body .= " \n ()" ;
@@ -1502,10 +1576,10 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
15021576 }
15031577 }
15041578 elsif ($firstop ) {
1505- $body = $self -> deparse($root -> first, 0);
1579+ $body . = $self -> deparse($root -> first, 0);
15061580 }
15071581 else {
1508- $body = ' ;' ; # stub sub
1582+ $body . = ' ;' ; # stub sub
15091583 }
15101584
15111585 my $l = ' ' ;
@@ -6977,6 +7051,11 @@ sub pp_argdefelem {
69777051}
69787052
69797053
7054+ sub pp_multiparam {
7055+ die " Unable to handle PP_MULTIPARAM outside of a regular subroutine signature position" ;
7056+ }
7057+
7058+
69807059sub pp_pushdefer {
69817060 my $self = shift ;
69827061 my ($op , $cx ) = @_ ;
0 commit comments