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