Initial Commit

This commit is contained in:
Riley Schneider
2025-12-03 16:38:10 +01:00
parent c5e26bf594
commit b732d8d4b5
17680 changed files with 5977495 additions and 2 deletions

View File

@@ -0,0 +1,75 @@
package PPI::Statement::Break;
=pod
=head1 NAME
PPI::Statement::Break - Statements which break out of normal statement flow
=head1 SYNOPSIS
last;
goto FOO;
next if condition();
return $foo;
redo;
=head1 INHERITANCE
PPI::Statement::Break
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
C<PPI::Statement::Break> is intended to represent statements that break
out of the normal statement flow control. This covers the basic
types C<'redo'>, C<'goto'>, C<'next'>, C<'last'> and C<'return'>.
=head1 METHODS
C<PPI::Statement::Break> has no additional methods beyond the default ones
provided by L<PPI::Statement>, L<PPI::Node> and L<PPI::Element>.
However, it is expected to gain methods for identifying the line to break
to, or the structure to break out of.
=cut
use strict;
use PPI::Statement ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement";
1;
=pod
=head1 TO DO
- Add the methods to identify the break target
- Add some proper unit testing
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,201 @@
package PPI::Statement::Compound;
=pod
=head1 NAME
PPI::Statement::Compound - Describes all compound statements
=head1 SYNOPSIS
# A compound if statement
if ( foo ) {
bar();
} else {
baz();
}
# A compound loop statement
foreach ( @list ) {
bar($_);
}
=head1 INHERITANCE
PPI::Statement::Compound
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
C<PPI::Statement::Compound> objects are used to describe all current forms
of compound statements, as described in L<perlsyn>.
This covers blocks using C<if>, C<unless>, C<for>, C<foreach>, C<while>,
and C<continue>. Please note this does B<not> cover "simple" statements
with trailing conditions. Please note also that "do" is also not part of
a compound statement.
# This is NOT a compound statement
my $foo = 1 if $condition;
# This is also not a compound statement
do { ... } until $condition;
=head1 METHODS
C<PPI::Statement::Compound> has a number of methods in addition to the
standard L<PPI::Statement>, L<PPI::Node> and L<PPI::Element> methods.
=cut
use strict;
use PPI::Statement ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement";
# Keyword type map
my %TYPES = (
'if' => 'if',
'unless' => 'if',
'while' => 'while',
'until' => 'while',
'for' => 'for',
'foreach' => 'foreach',
);
# Lexer clues
sub __LEXER__normal() { '' }
#####################################################################
# PPI::Statement::Compound analysis methods
=pod
=head2 type
The C<type> method returns the syntactic type of the compound statement.
There are four basic compound statement types.
The C<'if'> type includes all variations of the if and unless statements,
including any C<'elsif'> or C<'else'> parts of the compound statement.
The C<'while'> type describes the standard while and until statements, but
again does B<not> describes simple statements with a trailing while.
The C<'for'> type covers the C-style for loops, regardless of whether they
were declared using C<'for'> or C<'foreach'>.
The C<'foreach'> type covers loops that iterate over collections,
regardless of whether they were declared using C<'for'> or C<'foreach'>.
All of the compounds are a variation on one of these four.
Returns the simple string C<'if'>, C<'for'>, C<'foreach'> or C<'while'>,
or C<undef> if the type cannot be determined.
=cut
sub type {
my $self = shift;
my $p = 0; # Child position
my $Element = $self->schild($p) or return undef;
# A labelled statement
if ( $Element->isa('PPI::Token::Label') ) {
$Element = $self->schild(++$p) or return 'label';
}
# Most simple cases
my $content = $Element->content;
if ( $content =~ /^for(?:each)?\z/ ) {
$Element = $self->schild(++$p) or return $content;
if ( $Element->isa('PPI::Token') ) {
return 'foreach' if $Element->content =~ /^my|our|state\z/;
return 'foreach' if $Element->isa('PPI::Token::Symbol');
return 'foreach' if $Element->isa('PPI::Token::QuoteLike::Words');
}
if ( $Element->isa('PPI::Structure::List') ) {
return 'foreach';
}
return 'for';
}
return $TYPES{$content} if $Element->isa('PPI::Token::Word');
return 'continue' if $Element->isa('PPI::Structure::Block');
# Unknown (shouldn't exist?)
undef;
}
#####################################################################
# PPI::Node Methods
sub scope() { 1 }
#####################################################################
# PPI::Element Methods
sub _complete {
my $self = shift;
my $type = $self->type or die "Illegal compound statement type";
# Check the different types of compound statements
if ( $type eq 'if' ) {
# Unless the last significant child is a complete
# block, it must be incomplete.
my $child = $self->schild(-1) or return '';
$child->isa('PPI::Structure') or return '';
$child->braces eq '{}' or return '';
$child->_complete or return '';
# It can STILL be
} elsif ( $type eq 'while' ) {
die "CODE INCOMPLETE";
} else {
die "CODE INCOMPLETE";
}
}
1;
=pod
=head1 TO DO
- Write unit tests for this package
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,81 @@
package PPI::Statement::Data;
=pod
=head1 NAME
PPI::Statement::Data - The __DATA__ section of a file
=head1 SYNOPSIS
# Normal content
__DATA__
This: data
is: part
of: the
PPI::Statement::Data: object
=head1 INHERITANCE
PPI::Statement::Compound
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
C<PPI::Statement::Data> is a utility class designed to hold content in
the __DATA__ section of a file. It provides a single statement to hold
B<all> of the data.
=head1 METHODS
C<PPI::Statement::Data> has no additional methods beyond the default ones
provided by L<PPI::Statement>, L<PPI::Node> and L<PPI::Element>.
However, it is expected to gain methods for accessing the data directly,
(as a filehandle for example) just as you would access the data in the
Perl code itself.
=cut
use strict;
use PPI::Statement ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement";
# Data is never complete
sub _complete () { '' }
1;
=pod
=head1 TO DO
- Add the methods to read in the data
- Add some proper unit testing
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,79 @@
package PPI::Statement::End;
=pod
=head1 NAME
PPI::Statement::End - Content after the __END__ of a module
=head1 SYNOPSIS
# This is normal content
__END__
This is part of a PPI::Statement::End statement
=pod
This is not part of the ::End statement, it's POD
=cut
This is another PPI::Statement::End statement
=head1 INHERITANCE
PPI::Statement::End
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
C<PPI::Statement::End> is a utility class designed to serve as a contained
for all of the content after the __END__ tag in a file.
It doesn't cover the ENTIRE of the __END__ section, and can be interspersed
with L<PPI::Token::Pod> tokens.
=head1 METHODS
C<PPI::Statement::End> has no additional methods beyond the default ones
provided by L<PPI::Statement>, L<PPI::Node> and L<PPI::Element>.
=cut
use strict;
use PPI::Statement ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement";
# Once we have an __END__ we're done
sub _complete () { 1 }
1;
=pod
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,67 @@
package PPI::Statement::Expression;
=pod
=head1 NAME
PPI::Statement::Expression - A generic and non-specialised statement
=head1 SYNOPSIS
$foo = bar;
("Hello World!");
do_this();
=head1 INHERITANCE
PPI::Statement::Expression
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
A C<PPI::Statement::Expression> is a normal statement that is evaluated,
may or may not assign, may or may not have side effects, and has no special
or redeeming features whatsoever.
It provides a default for all statements that don't fit into any other
classes.
=head1 METHODS
C<PPI::Statement::Expression> has no additional methods beyond the default ones
provided by L<PPI::Statement>, L<PPI::Node> and L<PPI::Element>.
=cut
use strict;
use PPI::Statement ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement";
1;
=pod
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,90 @@
package PPI::Statement::Given;
=pod
=head1 NAME
PPI::Statement::Given - A given-when statement
=head1 SYNOPSIS
given ( foo ) {
say $_;
}
=head1 INHERITANCE
PPI::Statement::Given
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
C<PPI::Statement::Given> objects are used to describe switch statements, as
described in L<perlsyn>.
=head1 METHODS
C<PPI::Statement::Given> has no methods beyond those provided by the
standard L<PPI::Structure>, L<PPI::Node> and L<PPI::Element> methods.
=cut
use strict;
use PPI::Statement ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement";
# Lexer clues
sub __LEXER__normal() { '' }
sub _complete {
my $child = $_[0]->schild(-1);
return !! (
defined $child
and
$child->isa('PPI::Structure::Block')
and
$child->complete
);
}
#####################################################################
# PPI::Node Methods
sub scope() { 1 }
1;
=pod
=head1 TO DO
- Write unit tests for this package
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,265 @@
package PPI::Statement::Include;
=pod
=head1 NAME
PPI::Statement::Include - Statements that include other code
=head1 SYNOPSIS
# The following are all includes
use 5.006;
use strict;
use My::Module;
use constant FOO => 'Foo';
require Foo::Bar;
require "Foo/Bar.pm";
require $foo if 1;
no strict 'refs';
=head1 INHERITANCE
PPI::Statement::Include
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
Despite its name, the C<PPI::Statement::Include> class covers a number
of different types of statement that cover all statements starting with
C<use>, C<no> and C<require>.
But basically, they cover three situations.
Firstly, a dependency on a particular version of perl (for which the
C<version> method returns true), a pragma (for which the C<pragma> method
returns true), or the loading (and unloading via no) of modules.
=head1 METHODS
C<PPI::Statement::Include> has a number of methods in addition to the standard
L<PPI::Statement>, L<PPI::Node> and L<PPI::Element> methods.
=cut
use strict;
use PPI::Statement ();
use PPI::Statement::Include::Perl6 ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement";
=pod
=head2 type
The C<type> method returns the general type of statement (C<'use'>, C<'no'>
or C<'require'>).
Returns the type as a string, or C<undef> if the type cannot be detected.
=cut
sub type {
my $self = shift;
my $keyword = $self->schild(0) or return undef;
$keyword->isa('PPI::Token::Word') and $keyword->content;
}
=pod
=head2 module
The C<module> method returns the module name specified in any include
statement. This C<includes> pragma names, because pragma are implemented
as modules. (And lets face it, the definition of a pragma can be fuzzy
at the best of times in any case)
This covers all of these...
use strict;
use My::Module;
no strict;
require My::Module;
...but does not cover any of these...
use 5.006;
require 5.005;
require "explicit/file/name.pl";
Returns the module name as a string, or C<undef> if the include does
not specify a module name.
=cut
sub module {
my $self = shift;
my $module = $self->schild(1) or return undef;
$module->isa('PPI::Token::Word') and $module->content;
}
=pod
=head2 module_version
The C<module_version> method returns the minimum version of the module
required by the statement, if there is one.
=cut
sub module_version {
my $self = shift;
my $argument = $self->schild(3);
if ( $argument and $argument->isa('PPI::Token::Operator') ) {
return undef;
}
my $version = $self->schild(2) or return undef;
return undef unless $version->isa('PPI::Token::Number');
return $version;
}
=pod
=head2 pragma
The C<pragma> method checks for an include statement's use as a
pragma, and returns it if so.
Or at least, it claims to. In practice it's a lot harder to say exactly
what is or isn't a pragma, because the definition is fuzzy.
The C<intent> of a pragma is to modify the way in which the parser works.
This is done though the use of modules that do various types of internals
magic.
For now, PPI assumes that any "module name" that is only a set of
lowercase letters (and perhaps numbers, like C<use utf8;>). This
behaviour is expected to change, most likely to something that knows
the specific names of the various "pragmas".
Returns the name of the pragma, or false ('') if the include is not a
pragma.
=cut
sub pragma {
my $self = shift;
my $module = $self->module or return '';
$module =~ /^[a-z][a-z\d]*$/ ? $module : '';
}
=pod
=head2 version
The C<version> method checks for an include statement that introduces a
dependency on the version of C<perl> the code is compatible with.
This covers two specific statements.
use 5.006;
require 5.006;
Currently the version is returned as a string, although in future the version
may be returned as a L<version> object. If you want a numeric representation,
use C<version_literal()>. Returns false if the statement is not a version
dependency.
=cut
sub version {
my $self = shift;
my $version = $self->schild(1) or return undef;
$version->isa('PPI::Token::Number') ? $version->content : '';
}
=pod
=head2 version_literal
The C<version_literal> method has the same behavior as C<version()>, but the
version is returned as a numeric literal. Returns false if the statement is
not a version dependency.
=cut
sub version_literal {
my $self = shift;
my $version = $self->schild(1) or return undef;
$version->isa('PPI::Token::Number') ? $version->literal : '';
}
=pod
=head2 arguments
The C<arguments> method gives you the rest of the statement after the
module/pragma and module version, i.e. the stuff that will be used to
construct what gets passed to the module's C<import()> subroutine. This does
include the comma, etc. operators, but doesn't include non-significant direct
children or any final semicolon.
=cut
sub arguments {
my $self = shift;
my @args = $self->schildren;
# Remove the "use", "no" or "require"
shift @args;
# Remove the statement terminator
if (
$args[-1]->isa('PPI::Token::Structure')
and
$args[-1]->content eq ';'
) {
pop @args;
}
# Remove the module or perl version.
shift @args;
return unless @args;
if ( $args[0]->isa('PPI::Token::Number') ) {
my $after = $args[1] or return;
$after->isa('PPI::Token::Operator') or shift @args;
}
return @args;
}
1;
=pod
=head1 TO DO
- Write specific unit tests for this package
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,87 @@
package PPI::Statement::Include::Perl6;
=pod
=head1 NAME
PPI::Statement::Include::Perl6 - Inline Perl 6 file section
=head1 SYNOPSIS
use v6-alpha;
grammar My::Grammar {
...
}
=head1 INHERITANCE
PPI::Statement::Include::Perl6
isa PPI::Statement::Include
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
A C<PPI::Statement::Include::Perl6> is a special include statement that
indicates the start of a section of Perl 6 code inlined into a regular
Perl 5 code file.
The primary purpose of the class is to allow L<PPI> to provide at least
basic support for "6 in 5" modules like v6.pm;
Currently, PPI only supports starting a Perl 6 block. It does not
currently support changing back to Perl 5 again. Additionally all POD
and __DATA__ blocks and __END__ blocks will be included in the Perl 6
string and will not be parsed by PPI.
=cut
use strict;
use PPI::Statement::Include ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement::Include";
=pod
=head2 perl6
The C<perl6> method returns the block of Perl 6 code that is attached to
the "use v6...;" command.
=cut
sub perl6 {
$_[0]->{perl6};
}
1;
=pod
=head1 TO DO
- Write specific unit tests for this package
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,75 @@
package PPI::Statement::Null;
=pod
=head1 NAME
PPI::Statement::Null - A useless null statement
=head1 SYNOPSIS
my $foo = 1;
; # <-- Null statement
my $bar = 1;
=head1 INHERITANCE
PPI::Statement::Null
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
C<PPI::Statement::Null> is a utility class designed to handle situations
where PPI encounters a naked statement separator.
Although strictly speaking, the semicolon is a statement B<separator>
and not a statement B<terminator>, PPI considers a semicolon to be a
statement terminator under most circumstances.
In any case, the null statement has no purpose, and can be safely deleted
with no ill effect.
=head1 METHODS
C<PPI::Statement::Null> has no additional methods beyond the default ones
provided by L<PPI::Statement>, L<PPI::Node> and L<PPI::Element>.
=cut
use strict;
use PPI::Statement ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement";
# A null statement is not significant
sub significant() { '' }
1;
=pod
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,145 @@
package PPI::Statement::Package;
=pod
=head1 NAME
PPI::Statement::Package - A package statement
=head1 INHERITANCE
PPI::Statement::Package
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
Most L<PPI::Statement> subclasses are assigned based on the value of the
first token or word found in the statement. When PPI encounters a statement
starting with 'package', it converts it to a C<PPI::Statement::Package>
object.
When working with package statements, please remember that packages only
exist within their scope, and proper support for scoping has yet to be
completed in PPI.
However, if the immediate parent of the package statement is the
top level L<PPI::Document> object, then it can be considered to define
everything found until the next top-level "file scoped" package statement.
A file may, however, contain nested temporary package, in which case you
are mostly on your own :)
=head1 METHODS
C<PPI::Statement::Package> has a number of methods in addition to the standard
L<PPI::Statement>, L<PPI::Node> and L<PPI::Element> methods.
=cut
use strict;
use PPI::Statement ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement";
# Lexer clues
sub __LEXER__normal() { '' }
=pod
=head2 namespace
Most package declarations are simple, and just look something like
package Foo::Bar;
The C<namespace> method returns the name of the declared package, in the
above case 'Foo::Bar'. It returns this exactly as written and does not
attempt to clean up or resolve things like ::Foo to main::Foo.
If the package statement is done any different way, it returns false.
=cut
sub namespace {
my $self = shift;
my $namespace = $self->schild(1) or return '';
$namespace->isa('PPI::Token::Word')
? $namespace->content
: '';
}
=pod
=head2 version
Some package declarations may include a version:
package Foo::Bar 1.23;
package Baz v1.23;
The C<version> method returns the stringified version as seen in the
document (if any), otherwise the empty string.
=cut
sub version {
my $self = shift;
my $version = $self->schild(2) or return '';
$version->isa('PPI::Token::Structure')
? ''
: $version->content;
}
=pod
=head2 file_scoped
Regardless of whether it is named or not, the C<file_scoped> method will
test to see if the package declaration is a top level "file scoped"
statement or not, based on its location.
In general, returns true if it is a "file scoped" package declaration with
an immediate parent of the top level Document, or false if not.
Note that if the PPI DOM tree B<does not> have a PPI::Document object at
as the root element, this will return false. Likewise, it will also return
false if the root element is a L<PPI::Document::Fragment>, as a fragment of
a file does not represent a scope.
=cut
sub file_scoped {
my $self = shift;
my ($Parent, $Document) = ($self->parent, $self->top);
$Parent and $Document and $Parent == $Document
and $Document->isa('PPI::Document')
and ! $Document->isa('PPI::Document::Fragment');
}
1;
=pod
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,124 @@
package PPI::Statement::Scheduled;
=pod
=head1 NAME
PPI::Statement::Scheduled - A scheduled code block
=head1 INHERITANCE
PPI::Statement::Scheduled
isa PPI::Statement::Sub
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
A scheduled code block is one that is intended to be run at a specific
time during the loading process.
There are five types of scheduled block:
BEGIN {
# Executes as soon as this block is fully defined
...
}
CHECK {
# Executes after overall compile-phase in reverse order
...
}
UNITCHECK {
# Executes after compile-phase of individual module in reverse order
...
}
INIT {
# Executes just before run-time
...
}
END {
# Executes as late as possible in reverse order
...
}
Technically these scheduled blocks are actually subroutines, and in fact
may have 'sub' in front of them.
=head1 METHODS
=cut
use strict;
use PPI::Statement::Sub ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement::Sub";
sub __LEXER__normal() { '' }
sub _complete {
my $child = $_[0]->schild(-1);
return !! (
defined $child
and
$child->isa('PPI::Structure::Block')
and
$child->complete
);
}
=pod
=head2 type
The C<type> method returns the type of scheduled block, which should always be
one of C<'BEGIN'>, C<'CHECK'>, C<'UNITCHECK'>, C<'INIT'> or C<'END'>.
=cut
sub type {
my $self = shift;
my @children = $self->schildren or return undef;
$children[0]->content eq 'sub'
? $children[1]->content
: $children[0]->content;
}
# This is actually the same as Sub->name
sub name {
shift->type(@_);
}
1;
=pod
=head1 TO DO
- Write unit tests for this package
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,221 @@
package PPI::Statement::Sub;
=pod
=head1 NAME
PPI::Statement::Sub - Subroutine declaration
=head1 INHERITANCE
PPI::Statement::Sub
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
Except for the special BEGIN, CHECK, UNITCHECK, INIT, and END subroutines
(which are part of L<PPI::Statement::Scheduled>) all subroutine declarations
are lexed as a PPI::Statement::Sub object.
Primarily, this means all of the various C<sub foo {}> statements, but also
forward declarations such as C<sub foo;> or C<sub foo($);>. It B<does not>
include anonymous subroutines, as these are merely part of a normal statement.
=head1 METHODS
C<PPI::Statement::Sub> has a number of methods in addition to the standard
L<PPI::Statement>, L<PPI::Node> and L<PPI::Element> methods.
=cut
use strict;
use List::Util ();
use Params::Util qw{_INSTANCE};
use PPI::Statement ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement";
# Lexer clue
sub __LEXER__normal() { '' }
sub _complete {
my $child = $_[0]->schild(-1);
return !! (
defined $child
and
$child->isa('PPI::Structure::Block')
and
$child->complete
);
}
#####################################################################
# PPI::Statement::Sub Methods
=pod
=head2 name
The C<name> method returns the name of the subroutine being declared.
In some rare cases such as a naked C<sub> at the end of the file, this may return
false.
=cut
sub name {
my ($self) = @_;
# Usually the second token is the name.
my $token = $self->schild(1);
return $token->content
if defined $token and $token->isa('PPI::Token::Word');
# In the case of special subs whose 'sub' can be omitted (AUTOLOAD
# or DESTROY), the name will be the first token.
$token = $self->schild(0);
return $token->content
if defined $token and $token->isa('PPI::Token::Word');
return '';
}
=pod
=head2 prototype
If it has one, the C<prototype> method returns the subroutine's prototype.
It is returned in the same format as L<PPI::Token::Prototype/prototype>,
cleaned and removed from its brackets.
Returns the subroutine's prototype, or undef if the subroutine does not
define one. Note that when the sub has an empty prototype (C<()>) the
return is an empty string.
=cut
sub prototype {
my $self = shift;
my $Prototype = List::Util::first {
_INSTANCE($_, 'PPI::Token::Prototype')
} $self->children;
defined($Prototype) ? $Prototype->prototype : undef;
}
=pod
=head2 block
With its name and implementation shared with L<PPI::Statement::Scheduled>,
the C<block> method finds and returns the actual Structure object of the
code block for this subroutine.
Returns false if this is a forward declaration, or otherwise does not have a
code block.
=cut
sub block {
my $self = shift;
my $lastchild = $self->schild(-1) or return '';
$lastchild->isa('PPI::Structure::Block') and $lastchild;
}
=pod
=head2 forward
The C<forward> method returns true if the subroutine declaration is a
forward declaration.
That is, it returns false if the subroutine has a code block, or true
if it does not.
=cut
sub forward {
! shift->block;
}
=pod
=head2 reserved
The C<reserved> method provides a convenience method for checking to see
if this is a special reserved subroutine. It does not check against any
particular list of reserved sub names, but just returns true if the name
is all uppercase, as defined in L<perlsub>.
Note that in the case of BEGIN, CHECK, UNITCHECK, INIT and END, these will be
defined as L<PPI::Statement::Scheduled> objects, not subroutines.
Returns true if it is a special reserved subroutine, or false if not.
=cut
sub reserved {
my $self = shift;
my $name = $self->name or return '';
# perlsub is silent on whether reserveds can contain:
# - underscores;
# we allow them due to existing practice like CLONE_SKIP and __SUB__.
# - numbers; we allow them by PPI tradition.
$name eq uc $name;
}
=pod
=head2 type
The C<type> method checks and returns the declaration type of the statement,
which will be one of 'my', 'our', or 'state'.
Returns a string of the type, or C<undef> if the type is not declared.
=cut
sub type {
my $self = shift;
# Get the first significant child
my @schild = grep { $_->significant } $self->children;
# Ignore labels
shift @schild if _INSTANCE($schild[0], 'PPI::Token::Label');
# Get the type
(_INSTANCE($schild[0], 'PPI::Token::Word') and $schild[0]->content =~ /^(my|our|state)$/)
? $schild[0]->content
: undef;
}
1;
=pod
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,68 @@
package PPI::Statement::Unknown;
=pod
=head1 NAME
PPI::Statement::Unknown - An unknown or transient statement
=head1 INHERITANCE
PPI::Statement::Unknown
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
The C<PPI::Statement::Unknown> class is used primarily during the lexing
process to hold elements that are known to be statement, but for which
the exact C<type> of statement is as yet unknown, and requires further
tokens in order to resolve the correct type.
They should not exist in a fully parse B<valid> document, and if any
exists they indicate either a problem in Document, or possibly (by
allowing it to get through unresolved) a bug in L<PPI::Lexer>.
=head1 METHODS
C<PPI::Statement::Unknown> has no additional methods beyond the
default ones provided by L<PPI::Statement>, L<PPI::Node> and
L<PPI::Element>.
=cut
use strict;
use PPI::Statement ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement";
# If one of these ends up in the final document,
# we're pretty much screwed. Just call it a day.
sub _complete () { 1 }
1;
=pod
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,80 @@
package PPI::Statement::UnmatchedBrace;
=pod
=head1 NAME
PPI::Statement::UnmatchedBrace - Isolated unmatched brace
=head1 SYNOPSIS
sub foo {
1;
}
} # <--- This is an unmatched brace
=head1 INHERITANCE
PPI::Statement::UnmatchedBrace
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
The C<PPI::Statement::UnmatchedBrace> class is a miscellaneous utility
class. Objects of this type should be rare, or not exist at all in normal
valid L<PPI::Document> objects.
It can be either a round ')', square ']' or curly '}' brace, this class
does not distinguish. Objects of this type are only allocated at a
structural level, not a lexical level (as they are lexically invalid
anyway).
The presence of a C<PPI::Statement::UnmatchedBrace> indicated a broken
or invalid document. Or maybe a bug in PPI, but B<far> more likely a
broken Document. :)
=head1 METHODS
C<PPI::Statement::UnmatchedBrace> has no additional methods beyond the
default ones provided by L<PPI::Statement>, L<PPI::Node> and
L<PPI::Element>.
=cut
use strict;
use PPI::Statement ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement";
# Once we've hit a naked unmatched brace we can never truly be complete.
# So instead we always just call it a day...
sub _complete () { 1 }
1;
=pod
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,195 @@
package PPI::Statement::Variable;
=pod
=head1 NAME
PPI::Statement::Variable - Variable declaration statements
=head1 SYNOPSIS
# All of the following are variable declarations
my $foo = 1;
my ($foo, $bar) = (1, 2);
our $foo = 1;
local $foo;
local $foo = 1;
LABEL: my $foo = 1;
=head1 INHERITANCE
PPI::Statement::Variable
isa PPI::Statement::Expression
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
The main intent of the C<PPI::Statement::Variable> class is to describe
simple statements that explicitly declare new local or global variables.
Note that this does not make it exclusively the only place where variables
are defined, and later on you should expect that the C<variables> method
will migrate deeper down the tree to either L<PPI::Statement> or
L<PPI::Node> to recognise this fact, but for now it stays here.
=head1 METHODS
=cut
use strict;
use Params::Util qw{_INSTANCE};
use PPI::Statement::Expression ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement::Expression";
=pod
=head2 type
The C<type> method checks and returns the declaration type of the statement,
which will be one of 'my', 'local', 'our', or 'state'.
Returns a string of the type, or C<undef> if the type cannot be detected
(which is probably a bug).
=cut
sub type {
my $self = shift;
# Get the first significant child
my @schild = grep { $_->significant } $self->children;
# Ignore labels
shift @schild if _INSTANCE($schild[0], 'PPI::Token::Label');
# Get the type
(_INSTANCE($schild[0], 'PPI::Token::Word') and $schild[0]->content =~ /^(my|local|our|state)$/)
? $schild[0]->content
: undef;
}
=pod
=head2 variables
As for several other PDOM Element types that can declare variables, the
C<variables> method returns a list of the canonical forms of the variables
defined by the statement.
Returns a list of the canonical string forms of variables, or the null list
if it is unable to find any variables.
=cut
sub variables {
map { $_->canonical } $_[0]->symbols;
}
=pod
=head2 symbols
Returns a list of the variables defined by the statement, as
L<PPI::Token::Symbol>s.
=cut
sub symbols {
my $self = shift;
# Get the children we care about
my @schild = grep { $_->significant } $self->children;
shift @schild if _INSTANCE($schild[0], 'PPI::Token::Label');
# If the second child is a symbol, return its name
if ( _INSTANCE($schild[1], 'PPI::Token::Symbol') ) {
return $schild[1];
}
# If it's a list, return as a list
if ( _INSTANCE($schild[1], 'PPI::Structure::List') ) {
my $Expression = $schild[1]->schild(0);
$Expression and
$Expression->isa('PPI::Statement::Expression') or return ();
# my and our are simpler than local
if (
$self->type eq 'my'
or
$self->type eq 'our'
or
$self->type eq 'state'
) {
return grep {
$_->isa('PPI::Token::Symbol')
} $Expression->schildren;
}
# Local is much more icky (potentially).
# Not that we are actually going to deal with it now,
# but having this separate is likely going to be needed
# for future bug reports about local() things.
# This is a slightly better way to check.
return grep {
$self->_local_variable($_)
} grep {
$_->isa('PPI::Token::Symbol')
} $Expression->schildren;
}
# erm... this is unexpected
();
}
sub _local_variable {
my ($self, $el) = @_;
# The last symbol should be a variable
my $n = $el->snext_sibling or return 1;
my $p = $el->sprevious_sibling;
if ( ! $p or $p eq ',' ) {
# In the middle of a list
return 1 if $n eq ',';
# The first half of an assignment
return 1 if $n eq '=';
}
# Lets say no for know... additional work
# should go here.
return '';
}
1;
=pod
=head1 TO DO
- Write unit tests for this
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut

View File

@@ -0,0 +1,100 @@
package PPI::Statement::When;
=pod
=head1 NAME
PPI::Statement::When - A when statement
=head1 SYNOPSIS
foreach ( qw/ foo bar baz / ) {
when ( m/b/ ) {
boing($_);
}
when ( m/f/ ) {
boom($_);
}
default {
tchak($_);
}
}
=head1 INHERITANCE
PPI::Statement::When
isa PPI::Statement
isa PPI::Node
isa PPI::Element
=head1 DESCRIPTION
C<PPI::Statement::When> objects are used to describe when and default
statements, as described in L<perlsyn>.
=head1 METHODS
C<PPI::Structure::When> has no methods beyond those provided by the
standard L<PPI::Structure>, L<PPI::Node> and L<PPI::Element> methods.
=cut
use strict;
use PPI::Statement ();
our $VERSION = '1.270'; # VERSION
our @ISA = "PPI::Statement";
# Lexer clues
sub __LEXER__normal() { '' }
sub _complete {
my $child = $_[0]->schild(-1);
return !! (
defined $child
and
$child->isa('PPI::Structure::Block')
and
$child->complete
);
}
#####################################################################
# PPI::Node Methods
sub scope() {
1;
}
1;
=pod
=head1 TO DO
- Write unit tests for this package
=head1 SUPPORT
See the L<support section|PPI/SUPPORT> in the main module.
=head1 AUTHOR
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2001 - 2011 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut