1 package PPI::Statement::Compound;
7 PPI::Statement::Compound - Describes all compound statements
11 # A compound if statement
18 # A compound loop statement
25 PPI::Statement::Compound
32 C<PPI::Statement::Compound> objects are used to describe all current forms
33 of compound statements, as described in L<perlsyn>.
35 This covers blocks using C<if>, C<unless>, C<for>, C<foreach>, C<while>,
36 and C<continue>. Please note this does B<not> cover "simple" statements
37 with trailing conditions. Please note also that "do" is also not part of
40 # This is NOT a compound statement
41 my $foo = 1 if $condition;
43 # This is also not a compound statement
44 do { ... } until $condition;
48 C<PPI::Statement::Compound> has a number of methods in addition to the
49 standard L<PPI::Statement>, L<PPI::Node> and L<PPI::Element> methods.
54 use List::MoreUtils ();
55 use PPI::Statement ();
57 use vars qw{$VERSION @ISA %TYPES};
60 @ISA = 'PPI::Statement';
69 'foreach' => 'foreach',
74 sub __LEXER__normal { '' }
80 #####################################################################
81 # PPI::Statement::Compound analysis methods
87 The C<type> method returns the syntactic type of the compound statement.
89 There are four basic compound statement types.
91 The C<'if'> type includes all variations of the if and unless statements,
92 including any C<'elsif'> or C<'else'> parts of the compound statement.
94 The C<'while'> type describes the standard while statement, but again does
95 B<not> describes simple statements with a trailing while.
97 The C<'for'> type covers the C-style for loops, regardless of whether they
98 were declared using C<'for'> or C<'foreach'>.
100 The C<'foreach'> type covers loops that iterate over collections,
101 regardless of whether they were declared using C<'for'> or C<'foreach'>.
103 All of the compounds are a variation on one of these four.
105 Returns the simple string C<'if'>, C<'for'>, C<'foreach'> or C<'while'>,
106 or C<undef> if the type cannot be determined.
108 =begin testing type 52
110 my $Document = PPI::Document->new(\<<'END_PERL');
122 foreach $x (@foo) { }
124 foreach my $x (@foo) { }
125 for state $x (@foo) { }
126 foreach state $x (@foo) { }
127 LABEL: for (@foo) { }
128 LABEL: foreach (@foo) { }
129 LABEL: for $x (@foo) { }
130 LABEL: foreach $x (@foo) { }
131 LABEL: for my $x (@foo) { }
132 LABEL: foreach my $x (@foo) { }
133 LABEL: for state $x (@foo) { }
134 LABEL: foreach state $x (@foo) { }
139 foreach $x qw{foo} { }
140 for my $x qw{foo} { }
141 foreach my $x qw{foo} { }
142 for state $x qw{foo} { }
143 foreach state $x qw{foo} { }
144 LABEL: for qw{foo} { }
145 LABEL: foreach qw{foo} { }
146 LABEL: for $x qw{foo} { }
147 LABEL: foreach $x qw{foo} { }
148 LABEL: for my $x qw{foo} { }
149 LABEL: foreach my $x qw{foo} { }
150 LABEL: for state $x qw{foo} { }
151 LABEL: foreach state $x qw{foo} { }
155 for ($x = 0 ; $x < 1; $x++) { }
156 foreach ($x = 0 ; $x < 1; $x++) { }
157 for (my $x = 0 ; $x < 1; $x++) { }
158 foreach (my $x = 0 ; $x < 1; $x++) { }
159 LABEL: for ( ; ; ) { }
160 LABEL: foreach ( ; ; ) { }
161 LABEL: for ($x = 0 ; $x < 1; $x++) { }
162 LABEL: foreach ($x = 0 ; $x < 1; $x++) { }
163 LABEL: for (my $x = 0 ; $x < 1; $x++) { }
164 LABEL: foreach (my $x = 0 ; $x < 1; $x++) { }
166 isa_ok( $Document, 'PPI::Document' );
168 my $statements = $Document->find('Statement::Compound');
169 is( scalar @{$statements}, 50, 'Found the 50 test statements' );
171 is( $statements->[0]->type, 'while', q<Type of while is "while"> );
172 is( $statements->[1]->type, 'while', q<Type of until is "while"> );
173 is( $statements->[2]->type, 'while', q<Type of while with label is "while"> );
174 is( $statements->[3]->type, 'while', q<Type of until with label is "while"> );
175 is( $statements->[4]->type, 'if', q<Type of if is "if"> );
176 is( $statements->[5]->type, 'if', q<Type of unless is "if"> );
178 foreach my $index (6..37) {
179 my $statement = $statements->[$index];
180 is( $statement->type, 'foreach', qq<Type is "foreach": $statement> );
183 foreach my $index (38..49) {
184 my $statement = $statements->[$index];
185 is( $statement->type, 'for', qq<Type is "for": $statement> );
194 my $p = 0; # Child position
195 my $Element = $self->schild($p) or return undef;
197 # A labelled statement
198 if ( $Element->isa('PPI::Token::Label') ) {
199 $Element = $self->schild(++$p) or return 'label';
203 my $content = $Element->content;
204 if ( $content =~ /^for(?:each)?\z/ ) {
205 $Element = $self->schild(++$p) or return $content;
206 if ( $Element->isa('PPI::Token') ) {
207 return 'foreach' if $Element->content =~ /^my|our|state\z/;
208 return 'foreach' if $Element->isa('PPI::Token::Symbol');
209 return 'foreach' if $Element->isa('PPI::Token::QuoteLike::Words');
211 if ( $Element->isa('PPI::Structure::List') ) {
216 return $TYPES{$content} if $Element->isa('PPI::Token::Word');
217 return 'continue' if $Element->isa('PPI::Structure::Block');
219 # Unknown (shouldn't exist?)
227 #####################################################################
236 #####################################################################
237 # PPI::Element Methods
241 my $type = $self->type or die "Illegal compound statement type";
243 # Check the different types of compound statements
244 if ( $type eq 'if' ) {
245 # Unless the last significant child is a complete
246 # block, it must be incomplete.
247 my $child = $self->schild(-1) or return '';
248 $child->isa('PPI::Structure') or return '';
249 $child->braces eq '{}' or return '';
250 $child->_complete or return '';
253 } elsif ( $type eq 'while' ) {
254 die "CODE INCOMPLETE";
256 die "CODE INCOMPLETE";
266 - Write unit tests for this package
270 See the L<support section|PPI/SUPPORT> in the main module.
274 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
278 Copyright 2001 - 2009 Adam Kennedy.
280 This program is free software; you can redistribute
281 it and/or modify it under the same terms as Perl itself.
283 The full text of the license can be found in the
284 LICENSE file included with this module.