Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the PPI CPAN distribution.

Report information
The Basics
Id: 46545
Status: new
Priority: 0/
Queue: PPI

People
Owner: Nobody in particular
Requestors: user42 [...] zip.com.au
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: suggest PPI::Statement::Include module_version and module_first_arg
Date: Sun, 31 May 2009 10:51:02 +1000
To: bug-PPI [...] rt.cpan.org
From: Kevin Ryde <user42 [...] zip.com.au>
As a suggestion, it'd be good if PPI::Statement::Include had methods like ->module_version and ->module_first_arg which returned and skipped (respectively) the module version number which perl checks. Eg. use Foo 1.0 'an arg'; would give back the 1.0 from $incl->module_version and the 'an arg' from $incl->module_first_arg. Both would be the respective PPI elements I think, in particular so you can then snext etc for the rest of the args. I've been getting some joy from code like below. The way I've got first_arg not returning ';' suits me, but maybe for maximum generality it shouldn't check that, just return it and let the caller notice it as the terminator etc. # This regexp is what Perl's toke.c S_force_version() demands, as of # versions 5.004 through 5.8.9. A version number in a "use" must start with # a digit and then have only digits, dots and underscores. In particular # other normal numeric forms like hex or exponential are not taken to be # version numbers, and even omitting the 0 from a decimal like ".25" is not # a version number. # our $use_module_version_number_re = qr/^v?[0-9][0-9._]*$/; # $inc is a PPI::Statement::Include. # If it has a version number for a module "use" or "no" then return that # element. As of PPI 1.203 there's no v-number parsing, so the version # element is always a PPI::Token::Number. # # A "require" is treated the same as "use" and "no", though a module version # number like "require Foo::Bar 1.5" is actually a syntax error. # # A module version is a literal number following the module name, with # either nothing else after it, or with no comma before the arglist. # sub include_module_version { my ($inc) = @_; # only a module style "use Foo", not a perl version num like "use 5.010" defined ($inc->module) || return undef; my $ver = $inc->schild(2) || return undef; # ENHANCE-ME: when PPI recognises v-strings may have to extend this $ver->isa('PPI::Token::Number') || return undef; $ver->content =~ $use_module_version_number_re or return undef; # when followed by a comma it's an argument not a version number, # eg. "use Foo 1.0, 'hello'" if (my $after = $ver->snext_sibling) { if ($after->isa('PPI::Token::Operator') && ($after eq ',' || $after eq '=>')) { return undef; } } return $ver; } # $inc is a PPI::Statement::Include. # Return the element which is the start of the first argument to its # import() or unimport(), for "use" or "no" respectively. # # A "require" is treated the same as "use" and "no", but arguments to it # like "require Foo::Bar '-init';" is in fact a syntax error. # sub include_module_first_arg { my ($inc) = @_; defined ($inc->module) || return undef; my $arg; if (my $ver = include_module_version ($inc)) { $arg = $ver->snext_sibling; } else { # eg. "use Foo 'xxx'" $arg = $inc->schild(2); } # don't return terminating ";" if ($arg && $arg->isa('PPI::Token::Structure') && $arg->content eq ';' && ! $arg->snext_sibling) { return undef; } return $arg; }
Subject: Re: [rt.cpan.org #46545] suggest PPI::Statement::Include module_version and module_first_arg
Date: Thu, 06 Aug 2009 08:45:54 +1000
To: bug-PPI [...] rt.cpan.org
From: Kevin Ryde <user42 [...] zip.com.au>
The module_version() of PPI 1.205 is too loose in what it takes to be a module version number. The $use_module_version_number_re of the code I posted is important because a float like use Foo 1e1; is not a module version number (rather an arg to the import). On the other hand use Foo 10 -3; _is_ a module version, and yet use Foo 10-3; is not. My code got this last one wrong. I think the key is whether there's following whitespace, along the lines below. A form use Foo 10 , 'x'; is a syntax error, but I take the 10 as a version number, because that's the reason it's a syntax error, ie. the "," is the start of the first arg. sub include_module_version { my ($inc) = @_; # only a module style "use Foo", not a perl version num like "use 5.010" defined ($inc->module) || return undef; my $ver = $inc->schild(2) || return undef; # ENHANCE-ME: when PPI recognises v-strings may have to extend this $ver->isa('PPI::Token::Number') || return undef; $ver->content =~ $use_module_version_number_re or return undef; # must be followed by whitespace, or comment, or end of statement, so # # use Foo 10 -3; <- version 10, arg -3 # use Foo 10-3; <- arg 7 # # use Foo 10# <- version 10, arg -3 # -3; # if (my $after = $ver->next_sibling) { unless ($after->isa('PPI::Token::Whitespace') || $after->isa('PPI::Token::Comment') || ($after->isa('PPI::Token::Structure') && $after eq ';')) { return undef; } } return $ver; }