| Filename | /Users/timbo/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/PPI/Statement/Compound.pm |
| Statements | Executed 19239 statements in 83.3ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 2355 | 3 | 2 | 61.6ms | 108ms | PPI::Statement::Compound::type |
| 1775 | 1 | 1 | 2.24ms | 2.24ms | PPI::Statement::Compound::__LEXER__normal |
| 2823 | 2 | 1 | 1.63ms | 1.63ms | PPI::Statement::Compound::CORE:match (opcode) |
| 1 | 1 | 1 | 12µs | 23µs | PPI::Statement::Compound::BEGIN@53 |
| 1 | 1 | 1 | 11µs | 11µs | PPI::Statement::Compound::BEGIN@57 |
| 1 | 1 | 1 | 6µs | 46µs | PPI::Statement::Compound::BEGIN@56 |
| 1 | 1 | 1 | 3µs | 3µs | PPI::Statement::Compound::BEGIN@54 |
| 0 | 0 | 0 | 0s | 0s | PPI::Statement::Compound::_complete |
| 0 | 0 | 0 | 0s | 0s | PPI::Statement::Compound::scope |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package PPI::Statement::Compound; | ||||
| 2 | |||||
| 3 | =pod | ||||
| 4 | |||||
| 5 | =head1 NAME | ||||
| 6 | |||||
| 7 | PPI::Statement::Compound - Describes all compound statements | ||||
| 8 | |||||
| 9 | =head1 SYNOPSIS | ||||
| 10 | |||||
| 11 | # A compound if statement | ||||
| 12 | if ( foo ) { | ||||
| 13 | bar(); | ||||
| 14 | } else { | ||||
| 15 | baz(); | ||||
| 16 | } | ||||
| 17 | |||||
| 18 | # A compound loop statement | ||||
| 19 | foreach ( @list ) { | ||||
| 20 | bar($_); | ||||
| 21 | } | ||||
| 22 | |||||
| 23 | =head1 INHERITANCE | ||||
| 24 | |||||
| 25 | PPI::Statement::Compound | ||||
| 26 | isa PPI::Statement | ||||
| 27 | isa PPI::Node | ||||
| 28 | isa PPI::Element | ||||
| 29 | |||||
| 30 | =head1 DESCRIPTION | ||||
| 31 | |||||
| 32 | C<PPI::Statement::Compound> objects are used to describe all current forms | ||||
| 33 | of compound statements, as described in L<perlsyn>. | ||||
| 34 | |||||
| 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 | ||||
| 38 | a compound statement. | ||||
| 39 | |||||
| 40 | # This is NOT a compound statement | ||||
| 41 | my $foo = 1 if $condition; | ||||
| 42 | |||||
| 43 | # This is also not a compound statement | ||||
| 44 | do { ... } until $condition; | ||||
| 45 | |||||
| 46 | =head1 METHODS | ||||
| 47 | |||||
| 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. | ||||
| 50 | |||||
| 51 | =cut | ||||
| 52 | |||||
| 53 | 2 | 18µs | 2 | 34µs | # spent 23µs (12+11) within PPI::Statement::Compound::BEGIN@53 which was called:
# once (12µs+11µs) by PPI::Statement::BEGIN@163 at line 53 # spent 23µs making 1 call to PPI::Statement::Compound::BEGIN@53
# spent 11µs making 1 call to strict::import |
| 54 | 2 | 18µs | 1 | 3µs | # spent 3µs within PPI::Statement::Compound::BEGIN@54 which was called:
# once (3µs+0s) by PPI::Statement::BEGIN@163 at line 54 # spent 3µs making 1 call to PPI::Statement::Compound::BEGIN@54 |
| 55 | |||||
| 56 | 2 | 43µs | 2 | 85µs | # spent 46µs (6+40) within PPI::Statement::Compound::BEGIN@56 which was called:
# once (6µs+40µs) by PPI::Statement::BEGIN@163 at line 56 # spent 46µs making 1 call to PPI::Statement::Compound::BEGIN@56
# spent 40µs making 1 call to vars::import |
| 57 | # spent 11µs within PPI::Statement::Compound::BEGIN@57 which was called:
# once (11µs+0s) by PPI::Statement::BEGIN@163 at line 70 | ||||
| 58 | 1 | 400ns | $VERSION = '1.215'; | ||
| 59 | 1 | 5µs | @ISA = 'PPI::Statement'; | ||
| 60 | |||||
| 61 | # Keyword type map | ||||
| 62 | 1 | 9µs | %TYPES = ( | ||
| 63 | 'if' => 'if', | ||||
| 64 | 'unless' => 'if', | ||||
| 65 | 'while' => 'while', | ||||
| 66 | 'until' => 'while', | ||||
| 67 | 'for' => 'for', | ||||
| 68 | 'foreach' => 'foreach', | ||||
| 69 | ); | ||||
| 70 | 1 | 294µs | 1 | 11µs | } # spent 11µs making 1 call to PPI::Statement::Compound::BEGIN@57 |
| 71 | |||||
| 72 | # Lexer clues | ||||
| 73 | 1775 | 6.85ms | # spent 2.24ms within PPI::Statement::Compound::__LEXER__normal which was called 1775 times, avg 1µs/call:
# 1775 times (2.24ms+0s) by PPI::Lexer::_lex_statement at line 626 of PPI/Lexer.pm, avg 1µs/call | ||
| 74 | |||||
| - - | |||||
| 79 | ##################################################################### | ||||
| 80 | # PPI::Statement::Compound analysis methods | ||||
| 81 | |||||
| 82 | =pod | ||||
| 83 | |||||
| 84 | =head2 type | ||||
| 85 | |||||
| 86 | The C<type> method returns the syntactic type of the compound statement. | ||||
| 87 | |||||
| 88 | There are four basic compound statement types. | ||||
| 89 | |||||
| 90 | The C<'if'> type includes all variations of the if and unless statements, | ||||
| 91 | including any C<'elsif'> or C<'else'> parts of the compound statement. | ||||
| 92 | |||||
| 93 | The C<'while'> type describes the standard while and until statements, but | ||||
| 94 | again does B<not> describes simple statements with a trailing while. | ||||
| 95 | |||||
| 96 | The C<'for'> type covers the C-style for loops, regardless of whether they | ||||
| 97 | were declared using C<'for'> or C<'foreach'>. | ||||
| 98 | |||||
| 99 | The C<'foreach'> type covers loops that iterate over collections, | ||||
| 100 | regardless of whether they were declared using C<'for'> or C<'foreach'>. | ||||
| 101 | |||||
| 102 | All of the compounds are a variation on one of these four. | ||||
| 103 | |||||
| 104 | Returns the simple string C<'if'>, C<'for'>, C<'foreach'> or C<'while'>, | ||||
| 105 | or C<undef> if the type cannot be determined. | ||||
| 106 | |||||
| 107 | =begin testing type 52 | ||||
| 108 | |||||
| 109 | my $Document = PPI::Document->new(\<<'END_PERL'); | ||||
| 110 | while (1) { } | ||||
| 111 | until (1) { } | ||||
| 112 | LABEL: while (1) { } | ||||
| 113 | LABEL: until (1) { } | ||||
| 114 | |||||
| 115 | if (1) { } | ||||
| 116 | unless (1) { } | ||||
| 117 | |||||
| 118 | for (@foo) { } | ||||
| 119 | foreach (@foo) { } | ||||
| 120 | for $x (@foo) { } | ||||
| 121 | foreach $x (@foo) { } | ||||
| 122 | for my $x (@foo) { } | ||||
| 123 | foreach my $x (@foo) { } | ||||
| 124 | for state $x (@foo) { } | ||||
| 125 | foreach state $x (@foo) { } | ||||
| 126 | LABEL: for (@foo) { } | ||||
| 127 | LABEL: foreach (@foo) { } | ||||
| 128 | LABEL: for $x (@foo) { } | ||||
| 129 | LABEL: foreach $x (@foo) { } | ||||
| 130 | LABEL: for my $x (@foo) { } | ||||
| 131 | LABEL: foreach my $x (@foo) { } | ||||
| 132 | LABEL: for state $x (@foo) { } | ||||
| 133 | LABEL: foreach state $x (@foo) { } | ||||
| 134 | |||||
| 135 | for qw{foo} { } | ||||
| 136 | foreach qw{foo} { } | ||||
| 137 | for $x qw{foo} { } | ||||
| 138 | foreach $x qw{foo} { } | ||||
| 139 | for my $x qw{foo} { } | ||||
| 140 | foreach my $x qw{foo} { } | ||||
| 141 | for state $x qw{foo} { } | ||||
| 142 | foreach state $x qw{foo} { } | ||||
| 143 | LABEL: for qw{foo} { } | ||||
| 144 | LABEL: foreach qw{foo} { } | ||||
| 145 | LABEL: for $x qw{foo} { } | ||||
| 146 | LABEL: foreach $x qw{foo} { } | ||||
| 147 | LABEL: for my $x qw{foo} { } | ||||
| 148 | LABEL: foreach my $x qw{foo} { } | ||||
| 149 | LABEL: for state $x qw{foo} { } | ||||
| 150 | LABEL: foreach state $x qw{foo} { } | ||||
| 151 | |||||
| 152 | for ( ; ; ) { } | ||||
| 153 | foreach ( ; ; ) { } | ||||
| 154 | for ($x = 0 ; $x < 1; $x++) { } | ||||
| 155 | foreach ($x = 0 ; $x < 1; $x++) { } | ||||
| 156 | for (my $x = 0 ; $x < 1; $x++) { } | ||||
| 157 | foreach (my $x = 0 ; $x < 1; $x++) { } | ||||
| 158 | LABEL: for ( ; ; ) { } | ||||
| 159 | LABEL: foreach ( ; ; ) { } | ||||
| 160 | LABEL: for ($x = 0 ; $x < 1; $x++) { } | ||||
| 161 | LABEL: foreach ($x = 0 ; $x < 1; $x++) { } | ||||
| 162 | LABEL: for (my $x = 0 ; $x < 1; $x++) { } | ||||
| 163 | LABEL: foreach (my $x = 0 ; $x < 1; $x++) { } | ||||
| 164 | END_PERL | ||||
| 165 | isa_ok( $Document, 'PPI::Document' ); | ||||
| 166 | |||||
| 167 | my $statements = $Document->find('Statement::Compound'); | ||||
| 168 | is( scalar @{$statements}, 50, 'Found the 50 test statements' ); | ||||
| 169 | |||||
| 170 | is( $statements->[0]->type, 'while', q<Type of while is "while"> ); | ||||
| 171 | is( $statements->[1]->type, 'while', q<Type of until is "while"> ); | ||||
| 172 | is( $statements->[2]->type, 'while', q<Type of while with label is "while"> ); | ||||
| 173 | is( $statements->[3]->type, 'while', q<Type of until with label is "while"> ); | ||||
| 174 | is( $statements->[4]->type, 'if', q<Type of if is "if"> ); | ||||
| 175 | is( $statements->[5]->type, 'if', q<Type of unless is "if"> ); | ||||
| 176 | |||||
| 177 | foreach my $index (6..37) { | ||||
| 178 | my $statement = $statements->[$index]; | ||||
| 179 | is( $statement->type, 'foreach', qq<Type is "foreach": $statement> ); | ||||
| 180 | } | ||||
| 181 | |||||
| 182 | foreach my $index (38..49) { | ||||
| 183 | my $statement = $statements->[$index]; | ||||
| 184 | is( $statement->type, 'for', qq<Type is "for": $statement> ); | ||||
| 185 | } | ||||
| 186 | |||||
| 187 | =end testing | ||||
| 188 | |||||
| 189 | =cut | ||||
| 190 | |||||
| 191 | # spent 108ms (61.6+46.0) within PPI::Statement::Compound::type which was called 2355 times, avg 46µs/call:
# 1768 times (47.0ms+30.3ms) by PPI::Lexer::_continues at line 733 of PPI/Lexer.pm, avg 44µs/call
# 504 times (8.13ms+13.3ms) by Perl::Critic::Policy::Variables::RequireLexicalLoopIterators::violates at line 51 of Perl/Critic/Policy/Variables/RequireLexicalLoopIterators.pm, avg 43µs/call
# 83 times (6.45ms+2.36ms) by PPI::Lexer::_round at line 999 of PPI/Lexer.pm, avg 106µs/call | ||||
| 192 | 2355 | 584µs | my $self = shift; | ||
| 193 | 2355 | 373µs | my $p = 0; # Child position | ||
| 194 | 2355 | 9.30ms | 4710 | 20.4ms | my $Element = $self->schild($p) or return undef; # spent 18.8ms making 2355 calls to PPI::Node::schild, avg 8µs/call
# spent 1.58ms making 2355 calls to PPI::Util::TRUE, avg 673ns/call |
| 195 | |||||
| 196 | # A labelled statement | ||||
| 197 | 2355 | 14.2ms | 2527 | 4.30ms | if ( $Element->isa('PPI::Token::Label') ) { # spent 2.95ms making 2355 calls to UNIVERSAL::isa, avg 1µs/call
# spent 1.30ms making 93 calls to PPI::Node::schild, avg 14µs/call
# spent 45µs making 79 calls to PPI::Util::TRUE, avg 575ns/call |
| 198 | $Element = $self->schild(++$p) or return 'label'; | ||||
| 199 | } | ||||
| 200 | |||||
| 201 | # Most simple cases | ||||
| 202 | 2341 | 3.13ms | 2341 | 9.58ms | my $content = $Element->content; # spent 6.18ms making 7 calls to PPI::Structure::content, avg 883µs/call
# spent 3.40ms making 2334 calls to PPI::Token::content, avg 1µs/call |
| 203 | 2341 | 16.3ms | 2341 | 1.24ms | if ( $content =~ /^for(?:each)?\z/ ) { # spent 1.24ms making 2341 calls to PPI::Statement::Compound::CORE:match, avg 529ns/call |
| 204 | 587 | 2.22ms | 1085 | 7.56ms | $Element = $self->schild(++$p) or return $content; # spent 7.26ms making 587 calls to PPI::Node::schild, avg 12µs/call
# spent 300µs making 498 calls to PPI::Util::TRUE, avg 602ns/call |
| 205 | 498 | 1.47ms | 498 | 425µs | if ( $Element->isa('PPI::Token') ) { # spent 349µs making 482 calls to UNIVERSAL::isa, avg 725ns/call
# spent 40µs making 8 calls to PPI::Structure::For::isa, avg 5µs/call
# spent 36µs making 8 calls to PPI::Structure::List::isa, avg 5µs/call |
| 206 | 482 | 11.7ms | 964 | 1.04ms | return 'foreach' if $Element->content =~ /^my|our|state\z/; # spent 646µs making 482 calls to PPI::Token::content, avg 1µs/call
# spent 391µs making 482 calls to PPI::Statement::Compound::CORE:match, avg 811ns/call |
| 207 | return 'foreach' if $Element->isa('PPI::Token::Symbol'); | ||||
| 208 | return 'foreach' if $Element->isa('PPI::Token::QuoteLike::Words'); | ||||
| 209 | } | ||||
| 210 | 16 | 36µs | 16 | 60µs | if ( $Element->isa('PPI::Structure::List') ) { # spent 32µs making 8 calls to PPI::Structure::For::isa, avg 4µs/call
# spent 28µs making 8 calls to PPI::Structure::List::isa, avg 4µs/call |
| 211 | return 'foreach'; | ||||
| 212 | } | ||||
| 213 | 8 | 20µs | return 'for'; | ||
| 214 | } | ||||
| 215 | 1754 | 16.7ms | 1754 | 1.38ms | return $TYPES{$content} if $Element->isa('PPI::Token::Word'); # spent 1.38ms making 1754 calls to UNIVERSAL::isa, avg 789ns/call |
| 216 | 7 | 40µs | 7 | 5µs | return 'continue' if $Element->isa('PPI::Structure::Block'); # spent 5µs making 7 calls to UNIVERSAL::isa, avg 700ns/call |
| 217 | |||||
| 218 | # Unknown (shouldn't exist?) | ||||
| 219 | undef; | ||||
| 220 | } | ||||
| 221 | |||||
| - - | |||||
| 226 | ##################################################################### | ||||
| 227 | # PPI::Node Methods | ||||
| 228 | |||||
| 229 | sub scope { 1 } | ||||
| 230 | |||||
| - - | |||||
| 235 | ##################################################################### | ||||
| 236 | # PPI::Element Methods | ||||
| 237 | |||||
| 238 | sub _complete { | ||||
| 239 | my $self = shift; | ||||
| 240 | my $type = $self->type or die "Illegal compound statement type"; | ||||
| 241 | |||||
| 242 | # Check the different types of compound statements | ||||
| 243 | if ( $type eq 'if' ) { | ||||
| 244 | # Unless the last significant child is a complete | ||||
| 245 | # block, it must be incomplete. | ||||
| 246 | my $child = $self->schild(-1) or return ''; | ||||
| 247 | $child->isa('PPI::Structure') or return ''; | ||||
| 248 | $child->braces eq '{}' or return ''; | ||||
| 249 | $child->_complete or return ''; | ||||
| 250 | |||||
| 251 | # It can STILL be | ||||
| 252 | } elsif ( $type eq 'while' ) { | ||||
| 253 | die "CODE INCOMPLETE"; | ||||
| 254 | } else { | ||||
| 255 | die "CODE INCOMPLETE"; | ||||
| 256 | } | ||||
| 257 | } | ||||
| 258 | |||||
| 259 | 1 | 2µs | 1; | ||
| 260 | |||||
| 261 | =pod | ||||
| 262 | |||||
| 263 | =head1 TO DO | ||||
| 264 | |||||
| 265 | - Write unit tests for this package | ||||
| 266 | |||||
| 267 | =head1 SUPPORT | ||||
| 268 | |||||
| 269 | See the L<support section|PPI/SUPPORT> in the main module. | ||||
| 270 | |||||
| 271 | =head1 AUTHOR | ||||
| 272 | |||||
| 273 | Adam Kennedy E<lt>adamk@cpan.orgE<gt> | ||||
| 274 | |||||
| 275 | =head1 COPYRIGHT | ||||
| 276 | |||||
| 277 | Copyright 2001 - 2011 Adam Kennedy. | ||||
| 278 | |||||
| 279 | This program is free software; you can redistribute | ||||
| 280 | it and/or modify it under the same terms as Perl itself. | ||||
| 281 | |||||
| 282 | The full text of the license can be found in the | ||||
| 283 | LICENSE file included with this module. | ||||
| 284 | |||||
| 285 | =cut | ||||
sub PPI::Statement::Compound::CORE:match; # opcode |