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,119 @@ 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+ # Optional parameter
1328+
1329+ if (length $param_padname [$parami ] > 1) {
1330+ # Named optional param
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+ # Anonymous optional param. This does not create or assign a
1341+ # variable but we still evaluate the defaulting expression for
1342+ # side-effects
1343+ my $cond = ( $defmode eq " //=" ) ? " defined \$ _[$argix ]" :
1344+ ( $defmode eq " ||=" ) ? " \$ _[$argix ]" :
1345+ " \@ _ > $argix " ;
1346+ $stmt = " $defexpr unless $cond " ;
1347+ }
1348+ }
1349+ else {
1350+ # Mandatory parameter
1351+
1352+ # Anonymous mandatory params can be entirely ignored. Their pad
1353+ # index will be zero.
1354+ $param_padix [$parami ] or next ;
1355+
1356+ $stmt .= " \$ _[$argix ]" ;
1357+ }
1358+
1359+ $code .= " $stmt ;\n " ;
12731360 }
12741361
12751362 if ($slurpy ) {
1276- push @sig , $slurpy_padix ? $self -> padname( $slurpy_padix ) : $slurpy ;
1363+ $code .= " my $slurpy_padname = \@ _[ $nparams .. \$ #_]; \n " ;
12771364 }
12781365
1279- return join (" , " , @sig );
1366+ $code =~ s / ;\n\z // ;
1367+ return $code ;
12801368}
12811369
12821370# deparse_argops(): deparse, if possible, a sequence of argcheck + argelem
@@ -1434,10 +1522,10 @@ Carp::confess("NULL in deparse_sub") if !defined($cv) || $cv->isa("B::NULL");
14341522Carp::confess(" SPECIAL in deparse_sub" ) if $cv -> isa(" B::SPECIAL" );
14351523 local $self -> {' curcop' } = $self -> {' curcop' };
14361524
1437- my $has_sig = $self -> feature_enabled(' signatures' );
1525+ my $use_feature_sig = $self -> feature_enabled(' signatures' );
14381526 if ($cv -> FLAGS & SVf_POK) {
14391527 my $myproto = $cv -> PV;
1440- if ($has_sig ) {
1528+ if ($use_feature_sig ) {
14411529 push @attrs , " prototype($myproto )" ;
14421530 }
14431531 else {
@@ -1457,7 +1545,7 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
14571545 local ($self -> {' curcvlex' });
14581546 local (@$self {qw' curstash warnings hints hinthash' })
14591547 = @$self {qw' curstash warnings hints hinthash' };
1460- my $body ;
1548+ my $body = " " ;
14611549 my $root = $cv -> ROOT;
14621550 local $B::overlay = {};
14631551 if (not null $root ) {
@@ -1471,16 +1559,21 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
14711559
14721560 # Try to deparse first subtree as a signature if possible.
14731561 # 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 ;
1562+ if ($$firstop and $firstop -> name eq ' null' and $firstop -> targ == OP_ARGCHECK) {
1563+ if ($use_feature_sig ) {
1564+ my ($mysig ) = $self -> deparse_multiparam($firstop , $cv , true) //
1565+ $self -> deparse_argops($firstop , $cv );
1566+ if (defined $mysig ) {
1567+ $sig = $mysig ;
1568+ $firstop = $is_list ? $firstop -> sibling : undef ;
1569+ }
1570+ }
1571+ else {
1572+ my $prelude = $self -> deparse_multiparam($firstop , $cv , false);
1573+ if (defined $prelude ) {
1574+ $body .= $prelude ;
1575+ $firstop = $is_list ? $firstop -> sibling : undef ;
1576+ }
14841577 }
14851578 }
14861579
@@ -1489,8 +1582,8 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
14891582 for (my $o = $firstop ; $$o ; $o =$o -> sibling) {
14901583 push @ops , $o ;
14911584 }
1492- $body = $self -> lineseq(undef , 0, @ops )." ;" ;
1493- if (!$has_sig and $ops [-1]-> name =~ / ^(next|db)state$ / ) {
1585+ $body . = $self -> lineseq(undef , 0, @ops )." ;" ;
1586+ if (!$use_feature_sig and $ops [-1]-> name =~ / ^(next|db)state$ / ) {
14941587 # this handles void context in
14951588 # use feature signatures; sub ($=1) {}
14961589 $body .= " \n ()" ;
@@ -1502,10 +1595,10 @@ Carp::confess("SPECIAL in deparse_sub") if $cv->isa("B::SPECIAL");
15021595 }
15031596 }
15041597 elsif ($firstop ) {
1505- $body = $self -> deparse($root -> first, 0);
1598+ $body . = $self -> deparse($root -> first, 0);
15061599 }
15071600 else {
1508- $body = ' ;' ; # stub sub
1601+ $body . = ' ;' ; # stub sub
15091602 }
15101603
15111604 my $l = ' ' ;
@@ -6977,6 +7070,11 @@ sub pp_argdefelem {
69777070}
69787071
69797072
7073+ sub pp_multiparam {
7074+ die " Unable to handle PP_MULTIPARAM outside of a regular subroutine signature position" ;
7075+ }
7076+
7077+
69807078sub pp_pushdefer {
69817079 my $self = shift ;
69827080 my ($op , $cx ) = @_ ;
@@ -7436,6 +7534,31 @@ want to eval the result, you should prepend "sub subname ", or "sub "
74367534for an anonymous function constructor. Unless the sub was defined in
74377535the main:: package, the code will include a package declaration.
74387536
7537+ Normally, C<B::Deparse > will emit code that includes the L<feature> pragma
7538+ if required to enable features that are used in the fragment that follows.
7539+ However, as L</coderef2text> emits only the body of a subroutine and expects
7540+ the caller to prepend the C<sub > and optional name onto the beginning of it,
7541+ it will not have the opportunity to emit a C<use feature 'signatures' > if the
7542+ subroutine uses a signature, and the signatures feature is not enabled in the
7543+ ambient pragmas.
7544+
7545+ In the particular situation of a subroutine that uses the C<signatures >
7546+ feature to parse its arguments being passed to L</coderef2text> when the
7547+ feature is B<not > enabled in L</ambient_pragmas> , C<B::Deparse > will attempt
7548+ to emit pure-perl code that emulates the behaviour of the signature as closely
7549+ as possible. This is performed on a B<best-effort > basis. It is not
7550+ guaranteed to perfectly capture the semantics of the signature's behaviour,
7551+ only to offer a human-readable suggestion as to what it might do.
7552+ Furthermore, it is not guaranteed to be able to reproduce every possible
7553+ behaviour of signatures in future versions of Perl. It may be that a future
7554+ version introduces a behaviour that does not have a tidy way to express it in
7555+ this pure-perl emulation code without using the C<signatures > feature.
7556+
7557+ If this is of importance to you, make sure to use the L</ambient_pragmas> or
7558+ L</ambient_pragmas_from_caller> method to enable the C<signatures > feature,
7559+ ensuring that C<B::Deparse > will use it to deparse subroutines that use
7560+ signatures.
7561+
74397562=head1 BUGS
74407563
74417564=over 4
0 commit comments