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 | __TOKENIZER__commit | PPI::Token::Word::
14513 | 1 | 1 | 61.0ms | 66.1ms | __TOKENIZER__literal | PPI::Token::Word::
60995 | 7 | 1 | 50.6ms | 50.6ms | CORE:match (opcode) | PPI::Token::Word::
1 | 1 | 1 | 13µs | 13µs | BEGIN@42 | PPI::Token::Word::
1 | 1 | 1 | 11µs | 23µs | BEGIN@38 | PPI::Token::Word::
1 | 1 | 1 | 6µs | 52µs | BEGIN@41 | PPI::Token::Word::
1 | 1 | 1 | 3µs | 3µs | BEGIN@39 | PPI::Token::Word::
0 | 0 | 0 | 0s | 0s | __TOKENIZER__on_char | PPI::Token::Word::
0 | 0 | 0 | 0s | 0s | literal | PPI::Token::Word::
0 | 0 | 0 | 0s | 0s | method_call | PPI::Token::Word::
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 |