| Filename | /Users/timbo/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/PPI/Token/Word.pm |
| Statements | Executed 314623 statements in 567ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 15490 | 3 | 2 | 590ms | 1.45s | PPI::Token::Word::__TOKENIZER__commit |
| 14513 | 1 | 1 | 61.0ms | 66.1ms | PPI::Token::Word::__TOKENIZER__literal |
| 60995 | 7 | 1 | 50.6ms | 50.6ms | PPI::Token::Word::CORE:match (opcode) |
| 1 | 1 | 1 | 13µs | 13µs | PPI::Token::Word::BEGIN@42 |
| 1 | 1 | 1 | 11µs | 23µs | PPI::Token::Word::BEGIN@38 |
| 1 | 1 | 1 | 6µs | 52µs | PPI::Token::Word::BEGIN@41 |
| 1 | 1 | 1 | 3µs | 3µs | PPI::Token::Word::BEGIN@39 |
| 0 | 0 | 0 | 0s | 0s | PPI::Token::Word::__TOKENIZER__on_char |
| 0 | 0 | 0 | 0s | 0s | PPI::Token::Word::literal |
| 0 | 0 | 0 | 0s | 0s | PPI::Token::Word::method_call |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package PPI::Token::Word; | ||||
| 2 | |||||
| 3 | =pod | ||||
| 4 | |||||
| 5 | =head1 NAME | ||||
| 6 | |||||
| 7 | PPI::Token::Word - The generic "word" Token | ||||
| 8 | |||||
| 9 | =head1 INHERITANCE | ||||
| 10 | |||||
| 11 | PPI::Token::Word | ||||
| 12 | isa PPI::Token | ||||
| 13 | isa PPI::Element | ||||
| 14 | |||||
| 15 | =head1 DESCRIPTION | ||||
| 16 | |||||
| 17 | A C<PPI::Token::Word> object is a PPI-specific representation of several | ||||
| 18 | different types of word-like things, and is one of the most common Token | ||||
| 19 | classes found in typical documents. | ||||
| 20 | |||||
| 21 | Specifically, it includes not only barewords, but also any other valid | ||||
| 22 | Perl identifier including non-operator keywords and core functions, and | ||||
| 23 | any include C<::> separators inside it, as long as it fits the | ||||
| 24 | format of a class, function, etc. | ||||
| 25 | |||||
| 26 | =head1 METHODS | ||||
| 27 | |||||
| 28 | There are no methods available for C<PPI::Token::Word> beyond those | ||||
| 29 | provided by its L<PPI::Token> and L<PPI::Element> parent | ||||
| 30 | classes. | ||||
| 31 | |||||
| 32 | We expect to add additional methods to help further resolve a Word as | ||||
| 33 | a function, method, etc over time. If you need such a thing right | ||||
| 34 | now, look at L<Perl::Critic::Utils>. | ||||
| 35 | |||||
| 36 | =cut | ||||
| 37 | |||||
| 38 | 2 | 18µs | 2 | 34µs | # spent 23µs (11+12) within PPI::Token::Word::BEGIN@38 which was called:
# once (11µs+12µs) by PPI::Token::BEGIN@49 at line 38 # spent 23µs making 1 call to PPI::Token::Word::BEGIN@38
# spent 12µs making 1 call to strict::import |
| 39 | 2 | 18µs | 1 | 3µs | # spent 3µs within PPI::Token::Word::BEGIN@39 which was called:
# once (3µs+0s) by PPI::Token::BEGIN@49 at line 39 # spent 3µs making 1 call to PPI::Token::Word::BEGIN@39 |
| 40 | |||||
| 41 | 2 | 76µs | 2 | 99µs | # spent 52µs (6+47) within PPI::Token::Word::BEGIN@41 which was called:
# once (6µs+47µs) by PPI::Token::BEGIN@49 at line 41 # spent 52µs making 1 call to PPI::Token::Word::BEGIN@41
# spent 47µs making 1 call to vars::import |
| 42 | # spent 13µs within PPI::Token::Word::BEGIN@42 which was called:
# once (13µs+0s) by PPI::Token::BEGIN@49 at line 60 | ||||
| 43 | 1 | 400ns | $VERSION = '1.215'; | ||
| 44 | 1 | 5µs | @ISA = 'PPI::Token'; | ||
| 45 | |||||
| 46 | # Copy in OPERATOR from PPI::Token::Operator | ||||
| 47 | 1 | 900ns | *OPERATOR = *PPI::Token::Operator::OPERATOR; | ||
| 48 | |||||
| 49 | 1 | 11µs | %QUOTELIKE = ( | ||
| 50 | 'q' => 'Quote::Literal', | ||||
| 51 | 'qq' => 'Quote::Interpolate', | ||||
| 52 | 'qx' => 'QuoteLike::Command', | ||||
| 53 | 'qw' => 'QuoteLike::Words', | ||||
| 54 | 'qr' => 'QuoteLike::Regexp', | ||||
| 55 | 'm' => 'Regexp::Match', | ||||
| 56 | 's' => 'Regexp::Substitute', | ||||
| 57 | 'tr' => 'Regexp::Transliterate', | ||||
| 58 | 'y' => 'Regexp::Transliterate', | ||||
| 59 | ); | ||||
| 60 | 1 | 993µs | 1 | 13µs | } # spent 13µs making 1 call to PPI::Token::Word::BEGIN@42 |
| 61 | |||||
| 62 | =pod | ||||
| 63 | |||||
| 64 | =head2 literal | ||||
| 65 | |||||
| 66 | Returns the value of the Word as a string. This assumes (often | ||||
| 67 | incorrectly) that the Word is a bareword and not a function, method, | ||||
| 68 | keyword, etc. This differs from C<content> because C<Foo'Bar> expands | ||||
| 69 | to C<Foo::Bar>. | ||||
| 70 | |||||
| 71 | =begin testing literal 9 | ||||
| 72 | |||||
| 73 | my @pairs = ( | ||||
| 74 | "F", 'F', | ||||
| 75 | "Foo::Bar", 'Foo::Bar', | ||||
| 76 | "Foo'Bar", 'Foo::Bar', | ||||
| 77 | ); | ||||
| 78 | while ( @pairs ) { | ||||
| 79 | my $from = shift @pairs; | ||||
| 80 | my $to = shift @pairs; | ||||
| 81 | my $doc = PPI::Document->new( \"$from;" ); | ||||
| 82 | isa_ok( $doc, 'PPI::Document' ); | ||||
| 83 | my $word = $doc->find_first('Token::Word'); | ||||
| 84 | isa_ok( $word, 'PPI::Token::Word' ); | ||||
| 85 | is( $word->literal, $to, "The source $from becomes $to ok" ); | ||||
| 86 | } | ||||
| 87 | |||||
| 88 | =end testing | ||||
| 89 | |||||
| 90 | =cut | ||||
| 91 | |||||
| 92 | sub literal { | ||||
| 93 | my $self = shift; | ||||
| 94 | my $word = $self->content; | ||||
| 95 | |||||
| 96 | # Expand Foo'Bar to Foo::Bar | ||||
| 97 | $word =~ s/\'/::/g; | ||||
| 98 | |||||
| 99 | return $word; | ||||
| 100 | } | ||||
| 101 | |||||
| 102 | =pod | ||||
| 103 | |||||
| 104 | =head2 method_call | ||||
| 105 | |||||
| 106 | Answers whether this is the name of a method in a method call. Returns true if | ||||
| 107 | yes, false if no, and nothing if unknown. | ||||
| 108 | |||||
| 109 | =begin testing method_call 24 | ||||
| 110 | |||||
| 111 | my $Document = PPI::Document->new(\<<'END_PERL'); | ||||
| 112 | indirect $foo; | ||||
| 113 | indirect_class_with_colon Foo::; | ||||
| 114 | $bar->method_with_parentheses; | ||||
| 115 | print SomeClass->method_without_parentheses + 1; | ||||
| 116 | sub_call(); | ||||
| 117 | $baz->chained_from->chained_to; | ||||
| 118 | a_first_thing a_middle_thing a_last_thing; | ||||
| 119 | (first_list_element, second_list_element, third_list_element); | ||||
| 120 | first_comma_separated_word, second_comma_separated_word, third_comma_separated_word; | ||||
| 121 | single_bareword_statement; | ||||
| 122 | { bareword_no_semicolon_end_of_block } | ||||
| 123 | $buz{hash_key}; | ||||
| 124 | fat_comma_left_side => $thingy; | ||||
| 125 | END_PERL | ||||
| 126 | |||||
| 127 | isa_ok( $Document, 'PPI::Document' ); | ||||
| 128 | my $words = $Document->find('Token::Word'); | ||||
| 129 | is( scalar @{$words}, 23, 'Found the 23 test words' ); | ||||
| 130 | my %words = map { $_ => $_ } @{$words}; | ||||
| 131 | is( | ||||
| 132 | scalar $words{indirect}->method_call, | ||||
| 133 | undef, | ||||
| 134 | 'Indirect notation is unknown.', | ||||
| 135 | ); | ||||
| 136 | is( | ||||
| 137 | scalar $words{indirect_class_with_colon}->method_call, | ||||
| 138 | 1, | ||||
| 139 | 'Indirect notation with following word ending with colons is true.', | ||||
| 140 | ); | ||||
| 141 | is( | ||||
| 142 | scalar $words{method_with_parentheses}->method_call, | ||||
| 143 | 1, | ||||
| 144 | 'Method with parentheses is true.', | ||||
| 145 | ); | ||||
| 146 | is( | ||||
| 147 | scalar $words{method_without_parentheses}->method_call, | ||||
| 148 | 1, | ||||
| 149 | 'Method without parentheses is true.', | ||||
| 150 | ); | ||||
| 151 | is( | ||||
| 152 | scalar $words{print}->method_call, | ||||
| 153 | undef, | ||||
| 154 | 'Plain print is unknown.', | ||||
| 155 | ); | ||||
| 156 | is( | ||||
| 157 | scalar $words{SomeClass}->method_call, | ||||
| 158 | undef, | ||||
| 159 | 'Class in class method call is unknown.', | ||||
| 160 | ); | ||||
| 161 | is( | ||||
| 162 | scalar $words{sub_call}->method_call, | ||||
| 163 | 0, | ||||
| 164 | 'Subroutine call is false.', | ||||
| 165 | ); | ||||
| 166 | is( | ||||
| 167 | scalar $words{chained_from}->method_call, | ||||
| 168 | 1, | ||||
| 169 | 'Method that is chained from is true.', | ||||
| 170 | ); | ||||
| 171 | is( | ||||
| 172 | scalar $words{chained_to}->method_call, | ||||
| 173 | 1, | ||||
| 174 | 'Method that is chained to is true.', | ||||
| 175 | ); | ||||
| 176 | is( | ||||
| 177 | scalar $words{a_first_thing}->method_call, | ||||
| 178 | undef, | ||||
| 179 | 'First bareword is unknown.', | ||||
| 180 | ); | ||||
| 181 | is( | ||||
| 182 | scalar $words{a_middle_thing}->method_call, | ||||
| 183 | undef, | ||||
| 184 | 'Bareword in the middle is unknown.', | ||||
| 185 | ); | ||||
| 186 | is( | ||||
| 187 | scalar $words{a_last_thing}->method_call, | ||||
| 188 | 0, | ||||
| 189 | 'Bareword at the end is false.', | ||||
| 190 | ); | ||||
| 191 | foreach my $false_word ( | ||||
| 192 | qw< | ||||
| 193 | first_list_element second_list_element third_list_element | ||||
| 194 | first_comma_separated_word second_comma_separated_word third_comma_separated_word | ||||
| 195 | single_bareword_statement | ||||
| 196 | bareword_no_semicolon_end_of_block | ||||
| 197 | hash_key | ||||
| 198 | fat_comma_left_side | ||||
| 199 | > | ||||
| 200 | ) { | ||||
| 201 | is( | ||||
| 202 | scalar $words{$false_word}->method_call, | ||||
| 203 | 0, | ||||
| 204 | "$false_word is false.", | ||||
| 205 | ); | ||||
| 206 | } | ||||
| 207 | |||||
| 208 | =end testing | ||||
| 209 | |||||
| 210 | =cut | ||||
| 211 | |||||
| 212 | sub method_call { | ||||
| 213 | my $self = shift; | ||||
| 214 | |||||
| 215 | my $previous = $self->sprevious_sibling; | ||||
| 216 | if ( | ||||
| 217 | $previous | ||||
| 218 | and | ||||
| 219 | $previous->isa('PPI::Token::Operator') | ||||
| 220 | and | ||||
| 221 | $previous->content eq '->' | ||||
| 222 | ) { | ||||
| 223 | return 1; | ||||
| 224 | } | ||||
| 225 | |||||
| 226 | my $snext = $self->snext_sibling; | ||||
| 227 | return 0 unless $snext; | ||||
| 228 | |||||
| 229 | if ( | ||||
| 230 | $snext->isa('PPI::Structure::List') | ||||
| 231 | or | ||||
| 232 | $snext->isa('PPI::Token::Structure') | ||||
| 233 | or | ||||
| 234 | $snext->isa('PPI::Token::Operator') | ||||
| 235 | and ( | ||||
| 236 | $snext->content eq ',' | ||||
| 237 | or | ||||
| 238 | $snext->content eq '=>' | ||||
| 239 | ) | ||||
| 240 | ) { | ||||
| 241 | return 0; | ||||
| 242 | } | ||||
| 243 | |||||
| 244 | if ( | ||||
| 245 | $snext->isa('PPI::Token::Word') | ||||
| 246 | and | ||||
| 247 | $snext->content =~ m< \w :: \z >xms | ||||
| 248 | ) { | ||||
| 249 | return 1; | ||||
| 250 | } | ||||
| 251 | |||||
| 252 | return; | ||||
| 253 | } | ||||
| 254 | |||||
| 255 | =begin testing __TOKENIZER__on_char 27 | ||||
| 256 | |||||
| 257 | my $Document = PPI::Document->new(\<<'END_PERL'); | ||||
| 258 | $foo eq'bar'; | ||||
| 259 | $foo ne'bar'; | ||||
| 260 | $foo ge'bar'; | ||||
| 261 | $foo le'bar'; | ||||
| 262 | $foo gt'bar'; | ||||
| 263 | $foo lt'bar'; | ||||
| 264 | END_PERL | ||||
| 265 | |||||
| 266 | isa_ok( $Document, 'PPI::Document' ); | ||||
| 267 | my $words = $Document->find('Token::Operator'); | ||||
| 268 | is( scalar @{$words}, 6, 'Found the 6 test operators' ); | ||||
| 269 | |||||
| 270 | is( $words->[0], 'eq', q{$foo eq'bar'} ); | ||||
| 271 | is( $words->[1], 'ne', q{$foo ne'bar'} ); | ||||
| 272 | is( $words->[2], 'ge', q{$foo ge'bar'} ); | ||||
| 273 | is( $words->[3], 'le', q{$foo le'bar'} ); | ||||
| 274 | is( $words->[4], 'gt', q{$foo ht'bar'} ); | ||||
| 275 | is( $words->[5], 'lt', q{$foo lt'bar'} ); | ||||
| 276 | |||||
| 277 | $Document = PPI::Document->new(\<<'END_PERL'); | ||||
| 278 | q'foo'; | ||||
| 279 | qq'foo'; | ||||
| 280 | END_PERL | ||||
| 281 | |||||
| 282 | isa_ok( $Document, 'PPI::Document' ); | ||||
| 283 | $words = $Document->find('Token::Quote'); | ||||
| 284 | is( scalar @{$words}, 2, 'Found the 2 test quotes' ); | ||||
| 285 | |||||
| 286 | is( $words->[0], q{q'foo'}, q{q'foo'} ); | ||||
| 287 | is( $words->[1], q{qq'foo'}, q{qq'foo'} ); | ||||
| 288 | |||||
| 289 | $Document = PPI::Document->new(\<<'END_PERL'); | ||||
| 290 | qx'foo'; | ||||
| 291 | qw'foo'; | ||||
| 292 | qr'foo'; | ||||
| 293 | END_PERL | ||||
| 294 | |||||
| 295 | isa_ok( $Document, 'PPI::Document' ); | ||||
| 296 | $words = $Document->find('Token::QuoteLike'); | ||||
| 297 | is( scalar @{$words}, 3, 'Found the 3 test quotelikes' ); | ||||
| 298 | |||||
| 299 | is( $words->[0], q{qx'foo'}, q{qx'foo'} ); | ||||
| 300 | is( $words->[1], q{qw'foo'}, q{qw'foo'} ); | ||||
| 301 | is( $words->[2], q{qr'foo'}, q{qr'foo'} ); | ||||
| 302 | |||||
| 303 | $Document = PPI::Document->new(\<<'END_PERL'); | ||||
| 304 | m'foo'; | ||||
| 305 | s'foo'bar'; | ||||
| 306 | tr'fo'ba'; | ||||
| 307 | y'fo'ba'; | ||||
| 308 | END_PERL | ||||
| 309 | |||||
| 310 | isa_ok( $Document, 'PPI::Document' ); | ||||
| 311 | $words = $Document->find('Token::Regexp'); | ||||
| 312 | is( scalar @{$words}, 4, 'Found the 4 test quotelikes' ); | ||||
| 313 | |||||
| 314 | is( $words->[0], q{m'foo'}, q{m'foo'} ); | ||||
| 315 | is( $words->[1], q{s'foo'bar'}, q{s'foo'bar'} ); | ||||
| 316 | is( $words->[2], q{tr'fo'ba'}, q{tr'fo'ba'} ); | ||||
| 317 | is( $words->[3], q{y'fo'ba'}, q{y'fo'ba'} ); | ||||
| 318 | |||||
| 319 | $Document = PPI::Document->new(\<<'END_PERL'); | ||||
| 320 | pack'H*',$data; | ||||
| 321 | unpack'H*',$data; | ||||
| 322 | END_PERL | ||||
| 323 | |||||
| 324 | isa_ok( $Document, 'PPI::Document' ); | ||||
| 325 | $words = $Document->find('Token::Word'); | ||||
| 326 | is( scalar @{$words}, 2, 'Found the 2 test words' ); | ||||
| 327 | |||||
| 328 | is( $words->[0], 'pack', q{pack'H*',$data} ); | ||||
| 329 | is( $words->[1], 'unpack', q{unpack'H*',$data} ); | ||||
| 330 | |||||
| 331 | =end testing | ||||
| 332 | |||||
| 333 | =cut | ||||
| 334 | |||||
| 335 | 1 | 11µs | my %backoff = map { $_ => 1 } qw{ | ||
| 336 | eq ne ge le gt lt | ||||
| 337 | q qq qx qw qr m s tr y | ||||
| 338 | pack unpack | ||||
| 339 | }; | ||||
| 340 | |||||
| 341 | sub __TOKENIZER__on_char { | ||||
| 342 | my $class = shift; | ||||
| 343 | my $t = shift; | ||||
| 344 | |||||
| 345 | # Suck in till the end of the bareword | ||||
| 346 | my $rest = substr( $t->{line}, $t->{line_cursor} ); | ||||
| 347 | if ( $rest =~ /^(\w+(?:(?:\'|::)\w+)*(?:::)?)/ ) { | ||||
| 348 | my $word = $1; | ||||
| 349 | # Special Case: If we accidentally treat eq'foo' like | ||||
| 350 | # the word "eq'foo", then just make 'eq' (or whatever | ||||
| 351 | # else is in the %backoff hash. | ||||
| 352 | if ( $word =~ /^(\w+)'/ && $backoff{$1} ) { | ||||
| 353 | $word = $1; | ||||
| 354 | } | ||||
| 355 | $t->{token}->{content} .= $word; | ||||
| 356 | $t->{line_cursor} += length $word; | ||||
| 357 | |||||
| 358 | } | ||||
| 359 | |||||
| 360 | # We might be a subroutine attribute. | ||||
| 361 | my $tokens = $t->_previous_significant_tokens(1); | ||||
| 362 | if ( $tokens and $tokens->[0]->{_attribute} ) { | ||||
| 363 | $t->{class} = $t->{token}->set_class( 'Attribute' ); | ||||
| 364 | return $t->{class}->__TOKENIZER__commit( $t ); | ||||
| 365 | } | ||||
| 366 | |||||
| 367 | # Check for a quote like operator | ||||
| 368 | my $word = $t->{token}->{content}; | ||||
| 369 | if ( $QUOTELIKE{$word} and ! $class->__TOKENIZER__literal($t, $word, $tokens) ) { | ||||
| 370 | $t->{class} = $t->{token}->set_class( $QUOTELIKE{$word} ); | ||||
| 371 | return $t->{class}->__TOKENIZER__on_char( $t ); | ||||
| 372 | } | ||||
| 373 | |||||
| 374 | # Or one of the word operators | ||||
| 375 | if ( $OPERATOR{$word} and ! $class->__TOKENIZER__literal($t, $word, $tokens) ) { | ||||
| 376 | $t->{class} = $t->{token}->set_class( 'Operator' ); | ||||
| 377 | return $t->_finalize_token->__TOKENIZER__on_char( $t ); | ||||
| 378 | } | ||||
| 379 | |||||
| 380 | # Unless this is a simple identifier, at this point | ||||
| 381 | # it has to be a normal bareword | ||||
| 382 | if ( $word =~ /\:/ ) { | ||||
| 383 | return $t->_finalize_token->__TOKENIZER__on_char( $t ); | ||||
| 384 | } | ||||
| 385 | |||||
| 386 | # If the NEXT character in the line is a colon, this | ||||
| 387 | # is a label. | ||||
| 388 | my $char = substr( $t->{line}, $t->{line_cursor}, 1 ); | ||||
| 389 | if ( $char eq ':' ) { | ||||
| 390 | $t->{token}->{content} .= ':'; | ||||
| 391 | $t->{line_cursor}++; | ||||
| 392 | $t->{class} = $t->{token}->set_class( 'Label' ); | ||||
| 393 | |||||
| 394 | # If not a label, '_' on its own is the magic filehandle | ||||
| 395 | } elsif ( $word eq '_' ) { | ||||
| 396 | $t->{class} = $t->{token}->set_class( 'Magic' ); | ||||
| 397 | |||||
| 398 | } | ||||
| 399 | |||||
| 400 | # Finalise and process the character again | ||||
| 401 | $t->_finalize_token->__TOKENIZER__on_char( $t ); | ||||
| 402 | } | ||||
| 403 | |||||
| - - | |||||
| 406 | # We are committed to being a bareword. | ||||
| 407 | # Or so we would like to believe. | ||||
| 408 | # spent 1.45s (590ms+861ms) within PPI::Token::Word::__TOKENIZER__commit which was called 15490 times, avg 94µs/call:
# 15152 times (582ms+842ms) by PPI::Token::Whitespace::__TOKENIZER__on_char at line 206 of PPI/Token/Whitespace.pm, avg 94µs/call
# 336 times (8.08ms+19.0ms) by PPI::Token::Number::Version::__TOKENIZER__commit at line 129 of PPI/Token/Number/Version.pm, avg 80µs/call
# 2 times (44µs+83µs) by PPI::Token::Whitespace::__TOKENIZER__on_char at line 393 of PPI/Token/Whitespace.pm, avg 63µs/call | ||||
| 409 | 15490 | 5.51ms | my ($class, $t) = @_; | ||
| 410 | |||||
| 411 | # Our current position is the first character of the bareword. | ||||
| 412 | # Capture the bareword. | ||||
| 413 | 15490 | 6.91ms | my $rest = substr( $t->{line}, $t->{line_cursor} ); | ||
| 414 | 15490 | 71.1ms | 15490 | 30.7ms | unless ( $rest =~ /^((?!\d)\w+(?:(?:\'|::)\w+)*(?:::)?)/ ) { # spent 30.7ms making 15490 calls to PPI::Token::Word::CORE:match, avg 2µs/call |
| 415 | # Programmer error | ||||
| 416 | die "Fatal error... regex failed to match in '$rest' when expected"; | ||||
| 417 | } | ||||
| 418 | |||||
| 419 | # Special Case: If we accidentally treat eq'foo' like the word "eq'foo", | ||||
| 420 | # then unwind it and just make it 'eq' (or the other stringy comparitors) | ||||
| 421 | 15490 | 12.5ms | my $word = $1; | ||
| 422 | 15490 | 52.3ms | 15490 | 5.41ms | if ( $word =~ /^(\w+)'/ && $backoff{$1} ) { # spent 5.41ms making 15490 calls to PPI::Token::Word::CORE:match, avg 349ns/call |
| 423 | $word = $1; | ||||
| 424 | } | ||||
| 425 | |||||
| 426 | # Advance the position one after the end of the bareword | ||||
| 427 | 15490 | 5.57ms | $t->{line_cursor} += length $word; | ||
| 428 | |||||
| 429 | # We might be a subroutine attribute. | ||||
| 430 | 15490 | 21.8ms | 15490 | 200ms | my $tokens = $t->_previous_significant_tokens(1); # spent 200ms making 15490 calls to PPI::Tokenizer::_previous_significant_tokens, avg 13µs/call |
| 431 | 15490 | 9.67ms | if ( $tokens and $tokens->[0]->{_attribute} ) { | ||
| 432 | $t->_new_token( 'Attribute', $word ); | ||||
| 433 | return ($t->{line_cursor} >= $t->{line_length}) ? 0 | ||||
| 434 | : $t->{class}->__TOKENIZER__on_char($t); | ||||
| 435 | } | ||||
| 436 | |||||
| 437 | # Check for the end of the file | ||||
| 438 | 15490 | 2.33ms | if ( $word eq '__END__' ) { | ||
| 439 | # Create the token for the __END__ itself | ||||
| 440 | 144 | 209µs | 144 | 2.06ms | $t->_new_token( 'Separator', $1 ); # spent 2.06ms making 144 calls to PPI::Tokenizer::_new_token, avg 14µs/call |
| 441 | 144 | 179µs | 144 | 299µs | $t->_finalize_token; # spent 299µs making 144 calls to PPI::Tokenizer::_finalize_token, avg 2µs/call |
| 442 | |||||
| 443 | # Move into the End zone (heh) | ||||
| 444 | 144 | 93µs | $t->{zone} = 'PPI::Token::End'; | ||
| 445 | |||||
| 446 | # Add the rest of the line as a comment, and a whitespace newline | ||||
| 447 | # Anything after the __END__ on the line is "ignored". So we must | ||||
| 448 | # also ignore it, by turning it into a comment. | ||||
| 449 | 144 | 110µs | $rest = substr( $t->{line}, $t->{line_cursor} ); | ||
| 450 | 144 | 80µs | $t->{line_cursor} = length $t->{line}; | ||
| 451 | 144 | 523µs | 144 | 245µs | if ( $rest =~ /\n$/ ) { # spent 245µs making 144 calls to PPI::Token::Word::CORE:match, avg 2µs/call |
| 452 | 144 | 95µs | chomp $rest; | ||
| 453 | 144 | 40µs | $t->_new_token( 'Comment', $rest ) if length $rest; | ||
| 454 | 144 | 204µs | 144 | 1.02ms | $t->_new_token( 'Whitespace', "\n" ); # spent 1.02ms making 144 calls to PPI::Tokenizer::_new_token, avg 7µs/call |
| 455 | } else { | ||||
| 456 | $t->_new_token( 'Comment', $rest ) if length $rest; | ||||
| 457 | } | ||||
| 458 | 144 | 185µs | 144 | 308µs | $t->_finalize_token; # spent 308µs making 144 calls to PPI::Tokenizer::_finalize_token, avg 2µs/call |
| 459 | |||||
| 460 | 144 | 379µs | return 0; | ||
| 461 | } | ||||
| 462 | |||||
| 463 | # Check for the data section | ||||
| 464 | 15346 | 1.12ms | if ( $word eq '__DATA__' ) { | ||
| 465 | # Create the token for the __DATA__ itself | ||||
| 466 | $t->_new_token( 'Separator', "$1" ); | ||||
| 467 | $t->_finalize_token; | ||||
| 468 | |||||
| 469 | # Move into the Data zone | ||||
| 470 | $t->{zone} = 'PPI::Token::Data'; | ||||
| 471 | |||||
| 472 | # Add the rest of the line as the Data token | ||||
| 473 | $rest = substr( $t->{line}, $t->{line_cursor} ); | ||||
| 474 | $t->{line_cursor} = length $t->{line}; | ||||
| 475 | if ( $rest =~ /\n$/ ) { | ||||
| 476 | chomp $rest; | ||||
| 477 | $t->_new_token( 'Comment', $rest ) if length $rest; | ||||
| 478 | $t->_new_token( 'Whitespace', "\n" ); | ||||
| 479 | } else { | ||||
| 480 | $t->_new_token( 'Comment', $rest ) if length $rest; | ||||
| 481 | } | ||||
| 482 | $t->_finalize_token; | ||||
| 483 | |||||
| 484 | return 0; | ||||
| 485 | } | ||||
| 486 | |||||
| 487 | 15346 | 823µs | my $token_class; | ||
| 488 | 15346 | 85.7ms | 29859 | 72.5ms | if ( $word =~ /\:/ ) { # spent 66.1ms making 14513 calls to PPI::Token::Word::__TOKENIZER__literal, avg 5µs/call
# spent 6.39ms making 15346 calls to PPI::Token::Word::CORE:match, avg 416ns/call |
| 489 | # Since its not a simple identifier... | ||||
| 490 | $token_class = 'Word'; | ||||
| 491 | |||||
| 492 | } elsif ( $class->__TOKENIZER__literal($t, $word, $tokens) ) { | ||||
| 493 | $token_class = 'Word'; | ||||
| 494 | |||||
| 495 | } elsif ( $QUOTELIKE{$word} ) { | ||||
| 496 | # Special Case: A Quote-like operator | ||||
| 497 | 1055 | 1.55ms | 1055 | 36.4ms | $t->_new_token( $QUOTELIKE{$word}, $word ); # spent 36.4ms making 1055 calls to PPI::Tokenizer::_new_token, avg 35µs/call |
| 498 | 1055 | 5.48ms | 1055 | 138ms | return ($t->{line_cursor} >= $t->{line_length}) ? 0 # spent 138ms making 1055 calls to PPI::Token::_QuoteEngine::__TOKENIZER__on_char, avg 131µs/call |
| 499 | : $t->{class}->__TOKENIZER__on_char( $t ); | ||||
| 500 | |||||
| 501 | } elsif ( $OPERATOR{$word} ) { | ||||
| 502 | # Word operator | ||||
| 503 | $token_class = 'Operator'; | ||||
| 504 | |||||
| 505 | } else { | ||||
| 506 | # If the next character is a ':' then its a label... | ||||
| 507 | 12514 | 7.36ms | my $string = substr( $t->{line}, $t->{line_cursor} ); | ||
| 508 | 12514 | 51.6ms | 12514 | 6.81ms | if ( $string =~ /^(\s*:)(?!:)/ ) { # spent 6.81ms making 12514 calls to PPI::Token::Word::CORE:match, avg 544ns/call |
| 509 | 14 | 10µs | if ( $tokens and $tokens->[0]->{content} eq 'sub' ) { | ||
| 510 | # ... UNLESS its after 'sub' in which | ||||
| 511 | # case it is a sub name and an attribute | ||||
| 512 | # operator. | ||||
| 513 | # We COULD have checked this at the top | ||||
| 514 | # level of checks, but this would impose | ||||
| 515 | # an additional performance per-word | ||||
| 516 | # penalty, and every other case where the | ||||
| 517 | # attribute operator doesn't directly | ||||
| 518 | # touch the object name already works. | ||||
| 519 | $token_class = 'Word'; | ||||
| 520 | } else { | ||||
| 521 | 14 | 9µs | $word .= $1; | ||
| 522 | 14 | 9µs | $t->{line_cursor} += length($1); | ||
| 523 | 14 | 5µs | $token_class = 'Label'; | ||
| 524 | } | ||||
| 525 | } elsif ( $word eq '_' ) { | ||||
| 526 | $token_class = 'Magic'; | ||||
| 527 | } else { | ||||
| 528 | 12500 | 3.38ms | $token_class = 'Word'; | ||
| 529 | } | ||||
| 530 | } | ||||
| 531 | |||||
| 532 | # Create the new token and finalise | ||||
| 533 | 14291 | 16.5ms | 14291 | 166ms | $t->_new_token( $token_class, $word ); # spent 166ms making 14291 calls to PPI::Tokenizer::_new_token, avg 12µs/call |
| 534 | 14291 | 4.80ms | if ( $t->{line_cursor} >= $t->{line_length} ) { | ||
| 535 | # End of the line | ||||
| 536 | $t->_finalize_token; | ||||
| 537 | return 0; | ||||
| 538 | } | ||||
| 539 | 14291 | 91.8ms | 28582 | 35.5ms | $t->_finalize_token->__TOKENIZER__on_char($t); # spent 35.5ms making 14291 calls to PPI::Tokenizer::_finalize_token, avg 2µs/call
# spent 164ms making 14291 calls to PPI::Token::Whitespace::__TOKENIZER__on_char, avg 12µs/call, recursion: max depth 1, sum of overlapping time 164ms |
| 540 | } | ||||
| 541 | |||||
| 542 | # Is the word in a "forced" context, and thus cannot be either an | ||||
| 543 | # operator or a quote-like thing. This version is only useful | ||||
| 544 | # during tokenization. | ||||
| 545 | # spent 66.1ms (61.0+5.13) within PPI::Token::Word::__TOKENIZER__literal which was called 14513 times, avg 5µs/call:
# 14513 times (61.0ms+5.13ms) by PPI::Token::Word::__TOKENIZER__commit at line 488, avg 5µs/call | ||||
| 546 | 14513 | 6.25ms | my ($class, $t, $word, $tokens) = @_; | ||
| 547 | |||||
| 548 | # Is this a forced-word context? | ||||
| 549 | # i.e. Would normally be seen as an operator. | ||||
| 550 | 14513 | 60.3ms | unless ( $QUOTELIKE{$word} or $PPI::Token::Operator::OPERATOR{$word} ) { | ||
| 551 | return ''; | ||||
| 552 | } | ||||
| 553 | |||||
| 554 | # Check the cases when we have previous tokens | ||||
| 555 | 1999 | 1.32ms | my $rest = substr( $t->{line}, $t->{line_cursor} ); | ||
| 556 | 1999 | 584µs | if ( $tokens ) { | ||
| 557 | 1999 | 7.03ms | 1999 | 1.52ms | my $token = $tokens->[0] or return ''; # spent 1.52ms making 1999 calls to PPI::Util::TRUE, avg 762ns/call |
| 558 | |||||
| 559 | # We are forced if we are a method name | ||||
| 560 | 1999 | 952µs | return 1 if $token->{content} eq '->'; | ||
| 561 | |||||
| 562 | # We are forced if we are a sub name | ||||
| 563 | 1999 | 10.9ms | 1999 | 2.57ms | return 1 if $token->isa('PPI::Token::Word') && $token->{content} eq 'sub'; # spent 2.57ms making 1999 calls to UNIVERSAL::isa, avg 1µs/call |
| 564 | |||||
| 565 | # If we are contained in a pair of curly braces, | ||||
| 566 | # we are probably a bareword hash key | ||||
| 567 | 1999 | 1.36ms | 14 | 20µs | if ( $token->{content} eq '{' and $rest =~ /^\s*\}/ ) { # spent 20µs making 14 calls to PPI::Token::Word::CORE:match, avg 1µs/call |
| 568 | return 1; | ||||
| 569 | } | ||||
| 570 | } | ||||
| 571 | |||||
| 572 | # In addition, if the word is followed by => it is probably | ||||
| 573 | # also actually a word and not a regex. | ||||
| 574 | 1997 | 8.56ms | 1997 | 1.02ms | if ( $rest =~ /^\s*=>/ ) { # spent 1.02ms making 1997 calls to PPI::Token::Word::CORE:match, avg 509ns/call |
| 575 | return 1; | ||||
| 576 | } | ||||
| 577 | |||||
| 578 | # Otherwise we probably arn't forced | ||||
| 579 | 1995 | 8.37ms | ''; | ||
| 580 | } | ||||
| 581 | |||||
| 582 | 1 | 5µs | 1; | ||
| 583 | |||||
| 584 | =pod | ||||
| 585 | |||||
| 586 | =head1 TO DO | ||||
| 587 | |||||
| 588 | - Add C<function>, C<method> etc detector methods | ||||
| 589 | |||||
| 590 | =head1 SUPPORT | ||||
| 591 | |||||
| 592 | See the L<support section|PPI/SUPPORT> in the main module. | ||||
| 593 | |||||
| 594 | =head1 AUTHOR | ||||
| 595 | |||||
| 596 | Adam Kennedy E<lt>adamk@cpan.orgE<gt> | ||||
| 597 | |||||
| 598 | =head1 COPYRIGHT | ||||
| 599 | |||||
| 600 | Copyright 2001 - 2011 Adam Kennedy. | ||||
| 601 | |||||
| 602 | This program is free software; you can redistribute | ||||
| 603 | it and/or modify it under the same terms as Perl itself. | ||||
| 604 | |||||
| 605 | The full text of the license can be found in the | ||||
| 606 | LICENSE file included with this module. | ||||
| 607 | |||||
| 608 | =cut | ||||
# spent 50.6ms within PPI::Token::Word::CORE:match which was called 60995 times, avg 830ns/call:
# 15490 times (30.7ms+0s) by PPI::Token::Word::__TOKENIZER__commit at line 414, avg 2µs/call
# 15490 times (5.41ms+0s) by PPI::Token::Word::__TOKENIZER__commit at line 422, avg 349ns/call
# 15346 times (6.39ms+0s) by PPI::Token::Word::__TOKENIZER__commit at line 488, avg 416ns/call
# 12514 times (6.81ms+0s) by PPI::Token::Word::__TOKENIZER__commit at line 508, avg 544ns/call
# 1997 times (1.02ms+0s) by PPI::Token::Word::__TOKENIZER__literal at line 574, avg 509ns/call
# 144 times (245µs+0s) by PPI::Token::Word::__TOKENIZER__commit at line 451, avg 2µs/call
# 14 times (20µs+0s) by PPI::Token::Word::__TOKENIZER__literal at line 567, avg 1µs/call |