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,113 @@ 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+ my $stmt = " my $param_padname [$parami ] = " ;
1324+
1325+ if (my $defmode = $param_defmode [$parami ]) {
1326+ my $defexpr = $param_defexpr [$parami ];
1327+
1328+ # anonymous params with defaults don't create or assign a variable but
1329+ # still evaluate the defaulting expression for side-effects
1330+ if ( length $param_padname [$parami ] > 1 ) {
1331+ if ($defmode eq " =" ) {
1332+ $stmt .= " \@ _ > $argix ? \$ _[$argix ] : $defexpr " ;
1333+ }
1334+ else {
1335+ $defmode =~ s / =\z // ;
1336+ $stmt .= " \$ _[$argix ] $defmode $defexpr " ;
1337+ }
1338+ }
1339+ else {
1340+ my $cond = ( $defmode eq " //=" ) ? " defined \$ _[$argix ]" :
1341+ ( $defmode eq " ||=" ) ? " \$ _[$argix ]" :
1342+ " \@ _ > $argix " ;
1343+ $stmt = " $defexpr unless $cond " ;
1344+ }
1345+ }
1346+ else {
1347+ # anonymous params without defaulting expressions can be entirely ignored
1348+ $param_padix [$parami ] or next ;
1349+
1350+ $stmt .= " \$ _[$argix ]" ;
1351+ }
1352+
1353+ $code .= " $stmt ;\n " ;
12731354 }
12741355
12751356 if ($slurpy ) {
1276- push @sig , $slurpy_padix ? $self -> padname( $slurpy_padix ) : $slurpy ;
1357+ $code .= " my $slurpy_padname = \@ _[ $nparams .. \$ #_]; \n " ;
12771358 }
12781359
1279- return join (" , " , @sig );
1360+ $code =~ s / ;\n\z // ;
1361+ return $code ;
12801362}
12811363
12821364# deparse_argops(): deparse, if possible, a sequence of argcheck + argelem
@@ -1434,10 +1516,10 @@ Carp::confess("NULL in deparse_sub") if !defined($cv) || $cv->isa("B::NULL");
14341516Carp::confess(" SPECIAL in deparse_sub" ) if $cv -> isa(" B::SPECIAL" );
14351517 local $self -> {' curcop' } = $self -> {' curcop' };
14361518
1437- my $has_sig = $self -> feature_enabled(' signatures' );
1519+ my $use_feature_sig = $self -> feature_enabled(' signatures' );
14381520 if ($cv -> FLAGS & SVf_POK) {
14391521 my $myproto = $cv -> PV;
1440- if ($has_sig ) {
1522+ if ($use_feature_sig ) {
14411523 push @attrs , " prototype($myproto )" ;
14421524 }
14431525 else {
@@ -1457,7 +1539,7 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
14571539 local ($self -> {' curcvlex' });
14581540 local (@$self {qw' curstash warnings hints hinthash' })
14591541 = @$self {qw' curstash warnings hints hinthash' };
1460- my $body ;
1542+ my $body = " " ;
14611543 my $root = $cv -> ROOT;
14621544 local $B::overlay = {};
14631545 if (not null $root ) {
@@ -1471,16 +1553,21 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
14711553
14721554 # Try to deparse first subtree as a signature if possible.
14731555 # 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 ;
1556+ if ($$firstop and $firstop -> name eq ' null' and $firstop -> targ == OP_ARGCHECK) {
1557+ if ($use_feature_sig ) {
1558+ my ($mysig ) = $self -> deparse_multiparam($firstop , $cv , true) //
1559+ $self -> deparse_argops($firstop , $cv );
1560+ if (defined $mysig ) {
1561+ $sig = $mysig ;
1562+ $firstop = $is_list ? $firstop -> sibling : undef ;
1563+ }
1564+ }
1565+ else {
1566+ my $prelude = $self -> deparse_multiparam($firstop , $cv , false);
1567+ if (defined $prelude ) {
1568+ $body .= $prelude ;
1569+ $firstop = $is_list ? $firstop -> sibling : undef ;
1570+ }
14841571 }
14851572 }
14861573
@@ -1489,8 +1576,8 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
14891576 for (my $o = $firstop ; $$o ; $o =$o -> sibling) {
14901577 push @ops , $o ;
14911578 }
1492- $body = $self -> lineseq(undef , 0, @ops )." ;" ;
1493- if (!$has_sig and $ops [-1]-> name =~ / ^(next|db)state$ / ) {
1579+ $body . = $self -> lineseq(undef , 0, @ops )." ;" ;
1580+ if (!$use_feature_sig and $ops [-1]-> name =~ / ^(next|db)state$ / ) {
14941581 # this handles void context in
14951582 # use feature signatures; sub ($=1) {}
14961583 $body .= " \n ()" ;
@@ -1502,10 +1589,10 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
15021589 }
15031590 }
15041591 elsif ($firstop ) {
1505- $body = $self -> deparse($root -> first, 0);
1592+ $body . = $self -> deparse($root -> first, 0);
15061593 }
15071594 else {
1508- $body = ' ;' ; # stub sub
1595+ $body . = ' ;' ; # stub sub
15091596 }
15101597
15111598 my $l = ' ' ;
@@ -6977,6 +7064,11 @@ sub pp_argdefelem {
69777064}
69787065
69797066
7067+ sub pp_multiparam {
7068+ die " Unable to handle PP_MULTIPARAM outside of a regular subroutine signature position" ;
7069+ }
7070+
7071+
69807072sub pp_pushdefer {
69817073 my $self = shift ;
69827074 my ($op , $cx ) = @_ ;
@@ -7436,6 +7528,31 @@ want to eval the result, you should prepend "sub subname ", or "sub "
74367528for an anonymous function constructor. Unless the sub was defined in
74377529the main:: package, the code will include a package declaration.
74387530
7531+ Normally, C<B::Deparse > will emit code that includes the L<feature> pragma
7532+ if required to enable features that are used in the fragment that follows.
7533+ However, as L</coderef2text> emits only the body of a subroutine and expects
7534+ the caller to prepend the C<sub > and optional name onto the beginning of it,
7535+ it will not have the opportunity to emit a C<use feature 'signatures' > if the
7536+ subroutine uses a signature, and the signatures feature is not enabled in the
7537+ ambient pragmas.
7538+
7539+ In the particular situation of a subroutine that uses the C<signatures >
7540+ feature to parse its arguments being passed to L</coderef2text> when the
7541+ feature is B<not > enabled in L</ambient_pragmas> , C<B::Deparse > will attempt
7542+ to emit pure-perl code that emulates the behaviour of the signature as closely
7543+ as possible. This is performed on a B<best-effort > basis. It is not
7544+ guaranteed to perfectly capture the semantics of the signature's behaviour,
7545+ only to offer a human-readable suggestion as to what it might do.
7546+ Furthermore, it is not guaranteed to be able to reproduce every possible
7547+ behaviour of signatures in future versions of Perl. It may be that a future
7548+ version introduces a behaviour that does not have a tidy way to express it in
7549+ this pure-perl emulation code without using the C<signatures > feature.
7550+
7551+ If this is of importance to you, make sure to use the L</ambient_pragmas> or
7552+ L</ambient_pragmas_from_caller> method to enable the C<signatures > feature,
7553+ ensuring that C<B::Deparse > will use it to deparse subroutines that use
7554+ signatures.
7555+
74397556=head1 BUGS
74407557
74417558=over 4
0 commit comments