Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

122 parsing x #123

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
Revision history for Perl extension PPI
- Fix 1.218 regression where packages, subs, and words after
labels like /^x\d+/ would parse as x operator (GitHub #122)
(MOREGAN)

1.221_01
Summary:
Expand Down
34 changes: 32 additions & 2 deletions lib/PPI/Tokenizer.pm
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,35 @@ my %X_CAN_FOLLOW_OPERATOR = map { $_ => 1 } qw( -- ++ );
# These are the exceptions.
my %X_CAN_FOLLOW_STRUCTURE = map { $_ => 1 } qw( } ] \) );


# Something that looks like the x operator but follows a word
# is usually that word's argument.
# These are the exceptions.
# chop, chomp, dump are ambiguous because they can have either parms
# or no parms.
my %X_CAN_FOLLOW_WORD = map { $_ => 1 } qw(
endgrent
endhostent
endnetent
endprotoent
endpwent
endservent
fork
getgrent
gethostent
getlogin
getnetent
getppid
getprotoent
getpwent
getservent
setgrent
setpwent
time
times
wait
wantarray
__SUB__
);



Expand Down Expand Up @@ -552,7 +580,7 @@ sub _process_next_char {
return 0 if ++$self->{line_cursor} >= $self->{line_length};

# Pass control to the token class
my $result;
my $result;
unless ( $result = $self->{class}->__TOKENIZER__on_char( $self ) ) {
# undef is error. 0 is "Did stuff ourself, you don't have to do anything"
return defined $result ? 1 : undef;
Expand Down Expand Up @@ -771,6 +799,8 @@ sub _current_x_is_operator {
$prev
&& (!$prev->isa('PPI::Token::Operator') || $X_CAN_FOLLOW_OPERATOR{$prev})
&& (!$prev->isa('PPI::Token::Structure') || $X_CAN_FOLLOW_STRUCTURE{$prev})
&& (!$prev->isa('PPI::Token::Word') || $X_CAN_FOLLOW_WORD{$prev})
&& !$prev->isa('PPI::Token::Label')
;
}

Expand Down
10 changes: 6 additions & 4 deletions t/ppi_statement_package.t
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ BEGIN {
$PPI::XS_DISABLE = 1;
$PPI::Lexer::X_TOKENIZER ||= $ENV{X_TOKENIZER};
}
use Test::More tests => 14889;
use Test::More tests => 14949;
use Test::NoWarnings;
use PPI;

Expand Down Expand Up @@ -69,6 +69,8 @@ PERL_5_12_SYNTAX: {
keys %PPI::Token::Word::KEYWORDS,
# regression: misparsed as version string
'v10',
# regression GitHub #122: 'x' parsed as x operator
'x64',
# Other weird and/or special words, just in case
'__PACKAGE__',
'__FILE__',
Expand All @@ -81,11 +83,11 @@ PERL_5_12_SYNTAX: {
[ 'v1.2.3', 'PPI::Token::Number::Version' ],
[ '0.50 ', 'PPI::Token::Number::Float' ],
[ '0.50', 'PPI::Token::Number::Float' ],
[ '', '' ], # omit version
[ '', '' ], # omit version, traditional
);
my @blocks = (
[ ';', 'PPI::Token::Structure' ],
[ '{ 1 }', 'PPI::Structure::Block' ],
[ ';', 'PPI::Token::Structure' ], # traditional package syntax
[ '{ 1 }', 'PPI::Structure::Block' ], # 5.12 package syntax
);
$_->[2] = strip_ws_padding( $_->[0] ) for @versions, @blocks;

Expand Down
3 changes: 2 additions & 1 deletion t/ppi_statement_sub.t
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ BEGIN {
$PPI::Lexer::X_TOKENIZER ||= $ENV{X_TOKENIZER};
}

use Test::More tests => 6204;
use Test::More tests => 6208;
use Test::NoWarnings;
use PPI;

Expand All @@ -28,6 +28,7 @@ NAME: {
{ code => 'sub baz : method lvalue{}', name => 'baz' },
{ code => 'sub baz : method:lvalue{}', name => 'baz' },
{ code => 'sub baz (*) : method : lvalue{}', name => 'baz' },
{ code => 'sub x64 {}', name => 'x64' }, # should not be parsed as x operator
) {
my $code = $test->{code};
my $name = $test->{name};
Expand Down
58 changes: 54 additions & 4 deletions t/ppi_token_operator.t
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ BEGIN {
$PPI::XS_DISABLE = 1;
$PPI::Lexer::X_TOKENIZER ||= $ENV{X_TOKENIZER};
}
use Test::More tests => 1119;
use Test::More tests => 1142;
use Test::NoWarnings;
use PPI;

Expand Down Expand Up @@ -409,6 +409,17 @@ OPERATOR_X: {
'PPI::Token::Structure' => '}',
]
},
{
desc => 'label plus x',
code => 'LABEL: x64',
expected => [
'PPI::Statement::Compound' => 'LABEL:',
'PPI::Token::Label' => 'LABEL:',
'PPI::Token::Whitespace' => ' ',
'PPI::Statement' => 'x64',
'PPI::Token::Word' => 'x64',
]
},
);

# Exhaustively test when a preceding operator implies following
Expand Down Expand Up @@ -464,6 +475,45 @@ OPERATOR_X: {
push @tests, { desc => $desc, code => $code, expected => \@expected };
}


# Test that Perl builtins known to have a null prototype do not
# force a following 'x' to be a word.
my %noprotos = map { $_ => 1 } qw(
endgrent
endhostent
endnetent
endprotoent
endpwent
endservent
fork
getgrent
gethostent
getlogin
getnetent
getppid
getprotoent
getpwent
getservent
setgrent
setpwent
time
times
wait
wantarray
__SUB__
);
foreach my $noproto ( keys %noprotos ) {
my $code = "$noproto x3";
my @expected = (
'PPI::Token::Word' => $noproto,
'PPI::Token::Whitespace' => ' ',
'PPI::Token::Operator' => 'x',
'PPI::Token::Number' => '3',
);
my $desc = "builtin $noproto does not force following x to be a word";
push @tests, { desc => "builtin $noproto does not force following x to be a word", code => $code, expected => \@expected };
}

foreach my $test ( @tests ) {
my $d = PPI::Document->new( \$test->{code} );
my $tokens = $d->find( sub { 1; } );
Expand Down Expand Up @@ -524,7 +574,7 @@ OPERATOR_FAT_COMMA: {
'PPI::Token::Word' => $_,
'PPI::Token::Operator' => '=>',
'PPI::Token::Number' => '2',
]
]
} } keys %PPI::Token::Word::KEYWORDS ),
( map { {
desc=>$_,
Expand All @@ -537,7 +587,7 @@ OPERATOR_FAT_COMMA: {
'PPI::Token::Operator' => '=>',
'PPI::Token::Number' => '2',
'PPI::Token::Structure' => ')',
]
]
} } keys %PPI::Token::Word::KEYWORDS ),
( map { {
desc=>$_,
Expand All @@ -550,7 +600,7 @@ OPERATOR_FAT_COMMA: {
'PPI::Token::Operator' => '=>',
'PPI::Token::Number' => '2',
'PPI::Token::Structure' => '}',
]
]
} } keys %PPI::Token::Word::KEYWORDS ),
);

Expand Down