Permalink
Browse files

Fix for RT #74593: restore _parserepeat calling convection.

Parse::RecDescent 1.966_002 introduced a bug fix that changed the
calling convention for the internal function _parserepeat.  This
function was also used by Precompiled parsers distributed as parts of
other modules on CPAN, like Mail::IMAPClient and Module::ExtractUse.

This change restores the old old _parserepeat calling convention,
placing the new $_itempos argument at the end of the list.  An
unfortunate side effect of this change is that Precompiled parsers
that used versions 1.966_002 - 1.967_007 will break with this change.

Additionally, some Precompiled parsers available in CPAN modules (like
Module::ExtractUse) pre-dated Parse::RecDescent's setting of the
_precompiled member in the returned $parser.  Recent changes to
DESTROY to fix some memory leaks for dynamically generated parsers end
up removing those precompiled parser's functions.  Now
Parse::RecDescent sets _not_precompiled on runtime-generated parsers.
New precompiled parsers should delete this key prior to writing out
the parser.

LocalWords:  parserepeat
  • Loading branch information...
1 parent 9f7e6ea commit 8b4f6daab2e55f8169afe0bd64f7a6b31a58b12c @jtbraun committed Mar 14, 2012
Showing with 36 additions and 14 deletions.
  1. +6 −0 Changes
  2. +1 −1 README
  3. +29 −13 lib/Parse/RecDescent.pm
View
@@ -786,3 +786,9 @@ Revision history for Parse-RecDescent
scalar was passed to the parser. (RT.cpan.org #27705, thanks
Justin!)
+1.967_007 Tue Mar 13 22:28:00 2012
+
+ - Restore old _parserepeat calling convention. Change a
+ parser's DESTROY method to check for $self->{_not_precompiled}
+ instead of $self->{_precompiled}. (Fix for RT #74593).
+
View
2 README
@@ -1,4 +1,4 @@
-Parse::RecDescent version 1.967_007
+Parse::RecDescent version 1.967_008
NAME
View
@@ -119,7 +119,8 @@ sub Precompile
|| croak("Can't compile bad grammar")
if $grammar;
- $self->{_precompiled} = 1;
+ # Do not allow &DESTROY to remove the precompiled namespace
+ delete $self->{_not_precompiled};
foreach ( keys %{$self->{rules}} ) {
$self->{rules}{$_}{changed} = 1;
@@ -423,7 +424,7 @@ eval 'undef &' . $namespace . '::' . $self->{"name"} unless $parser->{saving};
my $code =
'
-# ARGS ARE: ($parser, $text; $repeating, $_noactions, $_itempos, \@args)
+# ARGS ARE: ($parser, $text; $repeating, $_noactions, \@args, $_itempos)
sub ' . $namespace . '::' . $self->{"name"} . '
{
my $thisparser = $_[0];
@@ -454,8 +455,8 @@ sub ' . $namespace . '::' . $self->{"name"} . '
my %item = ();
my $repeating = $_[2];
my $_noactions = $_[3];
- my $_itempos = $_[4];
- my @arg = defined $_[5] ? @{ &{$_[5]} } : ();
+ my @arg = defined $_[4] ? @{ &{$_[4]} } : ();
+ my $_itempos = $_[5];
my %arg = ($#arg & 01) ? @arg : (@arg, undef);
my $text;
my $lastsep;
@@ -1489,9 +1490,9 @@ sub code($$$$)
. $self->callsyntax($namespace.'::')
. '($thisparser,$text,$repeating,'
. ($self->{"lookahead"}?'1':'$_noactions')
- . ($check->{"itempos"}?',$itempos[$#itempos]':',undef')
. ($self->{argcode} ? ",sub { return $self->{argcode} }"
: ',sub { \\@arg }')
+ . ($check->{"itempos"}?',$itempos[$#itempos]':',undef')
. ')))
{
'.($self->{"lookahead"} ? '$text = $_savetext;' : '').'
@@ -1605,10 +1606,10 @@ sub code($$$$)
. $self->callsyntax($namespace.'::')
. ', ' . $min . ', ' . $max . ', '
. ($self->{"lookahead"}?'1':'$_noactions')
- . ($check->{"itempos"}?',$itempos[$#itempos]':',undef')
. ',$expectation,'
. ($self->{argcode} ? "sub { return $self->{argcode} }"
: 'sub { \\@arg }')
+ . ($check->{"itempos"}?',$itempos[$#itempos]':',undef')
. ')))
{
Parse::RecDescent::_trace(q{<<'.Parse::RecDescent::_matchtracemessage($self,1).' repeated subrule: ['
@@ -1895,7 +1896,7 @@ use vars qw ( $AUTOLOAD $VERSION $_FILENAME);
my $ERRORS = 0;
-our $VERSION = '1.967_007';
+our $VERSION = '1.967_008';
$VERSION = eval $VERSION;
$_FILENAME=__FILE__;
@@ -1924,6 +1925,13 @@ sub new ($$$$)
"localvars" => '',
"_AUTOACTION" => undef,
"_AUTOTREE" => undef,
+
+ # Precompiled parsers used to set _precompiled, but that
+ # wasn't present in some versions of Parse::RecDescent used to
+ # build precompiled parsers. Instead, set a new
+ # _not_precompiled flag, which is remove from future
+ # Precompiled parsers at build time.
+ "_not_precompiled" => 1,
};
@@ -1949,7 +1957,7 @@ sub DESTROY {
my ($self) = @_;
my $namespace = $self->{namespace};
$namespace =~ s/Parse::RecDescent:://;
- if (!$self->{_precompiled}) {
+ if ($self->{_not_precompiled}) {
# BEGIN WORKAROUND
# Perl has a bug that creates a circular reference between
# @ISA and that variable's stash:
@@ -3114,7 +3122,15 @@ sub AUTOLOAD # ($parser, $text; $linenum, @args)
croak "Unknown starting rule ($AUTOLOAD) called\n"
unless defined &$AUTOLOAD;
- my $retval = &{$AUTOLOAD}($_[0],$text,undef,undef,undef,$args);
+ my $retval = &{$AUTOLOAD}(
+ $_[0], # $parser
+ $text, # $text
+ undef, # $repeating
+ undef, # $_noactions
+ $args, # \@args
+ undef, # $_itempos
+ );
+
if (defined $retval)
{
@@ -3133,7 +3149,7 @@ sub AUTOLOAD # ($parser, $text; $linenum, @args)
sub _parserepeat($$$$$$$$$) # RETURNS A REF TO AN ARRAY OF MATCHES
{
- my ($parser, $text, $prod, $min, $max, $_noactions, $_itempos, $expectation, $argcode) = @_;
+ my ($parser, $text, $prod, $min, $max, $_noactions, $expectation, $argcode, $_itempos) = @_;
my @tokens = ();
my $itemposfirst;
@@ -3144,7 +3160,7 @@ sub _parserepeat($$$$$$$$$) # RETURNS A REF TO AN ARRAY OF MATCHES
my $_savetext = $text;
my $prevtextlen = length $text;
my $_tok;
- if (! defined ($_tok = &$prod($parser,$text,1,$_noactions,$_itempos,$argcode)))
+ if (! defined ($_tok = &$prod($parser,$text,1,$_noactions,$argcode,$_itempos)))
{
$text = $_savetext;
last;
@@ -3411,8 +3427,8 @@ Parse::RecDescent - Generate Recursive-Descent Parsers
=head1 VERSION
-This document describes version 1.967_007 of Parse::RecDescent
-released January 29th, 2012.
+This document describes version 1.967_008 of Parse::RecDescent
+released March 13th, 2012.
=head1 SYNOPSIS

0 comments on commit 8b4f6da

Please sign in to comment.