Filename | /Users/timbo/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/PPIx/Regexp/Node.pm |
Statements | Executed 20 statements in 1.14ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 12µs | 26µs | BEGIN@125 | PPIx::Regexp::Node::
1 | 1 | 1 | 12µs | 39µs | BEGIN@39 | PPIx::Regexp::Node::
1 | 1 | 1 | 11µs | 22µs | BEGIN@34 | PPIx::Regexp::Node::
1 | 1 | 1 | 8µs | 2.76ms | BEGIN@37 | PPIx::Regexp::Node::
1 | 1 | 1 | 7µs | 11µs | BEGIN@35 | PPIx::Regexp::Node::
1 | 1 | 1 | 7µs | 25µs | BEGIN@41 | PPIx::Regexp::Node::
1 | 1 | 1 | 7µs | 24µs | BEGIN@40 | PPIx::Regexp::Node::
1 | 1 | 1 | 6µs | 25µs | BEGIN@42 | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | __ANON__[:164] | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | __PPIX_LEXER__finalize | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | __PPIX_LEXER__record_capture_number | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | _find_routine | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | _nav | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | _new | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | child | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | children | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | contains | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | content | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | find | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | find_first | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | find_parents | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | first_element | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | last_element | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | perl_version_introduced | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | perl_version_removed | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | schild | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | schildren | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | tokens | PPIx::Regexp::Node::
0 | 0 | 0 | 0s | 0s | unescaped_content | PPIx::Regexp::Node::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | =head1 NAME | ||||
2 | |||||
3 | PPIx::Regexp::Node - Represent a container | ||||
4 | |||||
5 | =head1 SYNOPSIS | ||||
6 | |||||
7 | use PPIx::Regexp::Dumper; | ||||
8 | PPIx::Regexp::Dumper->new( 'qr{(foo)}' )->print(); | ||||
9 | |||||
10 | =head1 INHERITANCE | ||||
11 | |||||
12 | C<PPIx::Regexp::Node> is a | ||||
13 | L<PPIx::Regexp::Element|PPIx::Regexp::Element>. | ||||
14 | |||||
15 | C<PPIx::Regexp::Node> is the parent of L<PPIx::Regexp|PPIx::Regexp>, | ||||
16 | L<PPIx::Regexp::Node::Range|PPIx::Regexp::Node::Range> and | ||||
17 | L<PPIx::Regexp::Structure|PPIx::Regexp::Structure>. | ||||
18 | |||||
19 | =head1 DESCRIPTION | ||||
20 | |||||
21 | This class represents a structural element that contains other classes. | ||||
22 | It is an abstract class, not instantiated by the lexer. | ||||
23 | |||||
24 | =head1 METHODS | ||||
25 | |||||
26 | This class provides the following public methods. Methods not documented | ||||
27 | here are private, and unsupported in the sense that the author reserves | ||||
28 | the right to change or remove them without notice. | ||||
29 | |||||
30 | =cut | ||||
31 | |||||
32 | package PPIx::Regexp::Node; | ||||
33 | |||||
34 | 2 | 24µs | 2 | 34µs | # spent 22µs (11+11) within PPIx::Regexp::Node::BEGIN@34 which was called:
# once (11µs+11µs) by base::import at line 34 # spent 22µs making 1 call to PPIx::Regexp::Node::BEGIN@34
# spent 11µs making 1 call to strict::import |
35 | 2 | 21µs | 2 | 16µs | # spent 11µs (7+4) within PPIx::Regexp::Node::BEGIN@35 which was called:
# once (7µs+4µs) by base::import at line 35 # spent 11µs making 1 call to PPIx::Regexp::Node::BEGIN@35
# spent 4µs making 1 call to warnings::import |
36 | |||||
37 | 2 | 25µs | 2 | 2.76ms | # spent 2.76ms (8µs+2.75) within PPIx::Regexp::Node::BEGIN@37 which was called:
# once (8µs+2.75ms) by base::import at line 37 # spent 2.76ms making 1 call to PPIx::Regexp::Node::BEGIN@37
# spent 2.75ms making 1 call to base::import, recursion: max depth 1, sum of overlapping time 2.75ms |
38 | |||||
39 | 2 | 23µs | 2 | 46µs | # spent 39µs (12+27) within PPIx::Regexp::Node::BEGIN@39 which was called:
# once (12µs+27µs) by base::import at line 39 # spent 39µs making 1 call to PPIx::Regexp::Node::BEGIN@39
# spent 7µs making 1 call to List::Util::import |
40 | 2 | 21µs | 2 | 42µs | # spent 24µs (7+18) within PPIx::Regexp::Node::BEGIN@40 which was called:
# once (7µs+18µs) by base::import at line 40 # spent 24µs making 1 call to PPIx::Regexp::Node::BEGIN@40
# spent 18µs making 1 call to Exporter::import |
41 | 2 | 20µs | 2 | 42µs | # spent 25µs (7+18) within PPIx::Regexp::Node::BEGIN@41 which was called:
# once (7µs+18µs) by base::import at line 41 # spent 25µs making 1 call to PPIx::Regexp::Node::BEGIN@41
# spent 18µs making 1 call to Exporter::import |
42 | 2 | 219µs | 2 | 43µs | # spent 25µs (6+18) within PPIx::Regexp::Node::BEGIN@42 which was called:
# once (6µs+18µs) by base::import at line 42 # spent 25µs making 1 call to PPIx::Regexp::Node::BEGIN@42
# spent 18µs making 1 call to Exporter::import |
43 | |||||
44 | 1 | 600ns | our $VERSION = '0.036'; | ||
45 | |||||
46 | sub _new { | ||||
47 | my ( $class, @children ) = @_; | ||||
48 | ref $class and $class = ref $class; | ||||
49 | foreach my $elem ( @children ) { | ||||
50 | __instance( $elem, 'PPIx::Regexp::Element' ) or return; | ||||
51 | } | ||||
52 | my $self = { | ||||
53 | children => \@children, | ||||
54 | }; | ||||
55 | bless $self, $class; | ||||
56 | foreach my $elem ( @children ) { | ||||
57 | $elem->_parent( $self ); | ||||
58 | } | ||||
59 | return $self; | ||||
60 | } | ||||
61 | |||||
62 | =head2 child | ||||
63 | |||||
64 | my $kid = $node->child( 0 ); | ||||
65 | |||||
66 | This method returns the child at the given index. The indices start from | ||||
67 | zero, and negative indices are from the end of the list, so that | ||||
68 | C<< $node->child( -1 ) >> returns the last child of the node. | ||||
69 | |||||
70 | =cut | ||||
71 | |||||
72 | sub child { | ||||
73 | my ( $self, $inx ) = @_; | ||||
74 | defined $inx or $inx = 0; | ||||
75 | return $self->{children}[$inx]; | ||||
76 | } | ||||
77 | |||||
78 | =head2 children | ||||
79 | |||||
80 | This method returns the children of the Node. If called in scalar | ||||
81 | context it returns the number of children. | ||||
82 | |||||
83 | =cut | ||||
84 | |||||
85 | sub children { | ||||
86 | my ( $self ) = @_; | ||||
87 | return @{ $self->{children} }; | ||||
88 | } | ||||
89 | |||||
90 | =head2 contains | ||||
91 | |||||
92 | print $node->contains( $elem ) ? "yes\n" : "no\n"; | ||||
93 | |||||
94 | This method returns true if the given element is contained in the node, | ||||
95 | or false otherwise. | ||||
96 | |||||
97 | =cut | ||||
98 | |||||
99 | sub contains { | ||||
100 | my ( $self, $elem ) = @_; | ||||
101 | __instance( $elem, 'PPIx::Regexp::Element' ) or return; | ||||
102 | |||||
103 | my $addr = refaddr( $self ); | ||||
104 | |||||
105 | while ( $elem = $elem->parent() ) { | ||||
106 | $addr == refaddr( $elem ) and return 1; | ||||
107 | } | ||||
108 | |||||
109 | return; | ||||
110 | } | ||||
111 | |||||
112 | sub content { | ||||
113 | my ( $self ) = @_; | ||||
114 | return join( '', map{ $_->content() } $self->elements() ); | ||||
115 | } | ||||
116 | |||||
117 | =head2 elements | ||||
118 | |||||
119 | This method returns the elements in the Node. For a | ||||
120 | C<PPIx::Regexp::Node> proper, it is the same as C<children()>. | ||||
121 | |||||
122 | =cut | ||||
123 | |||||
124 | { | ||||
125 | 3 | 781µs | 2 | 40µs | # spent 26µs (12+14) within PPIx::Regexp::Node::BEGIN@125 which was called:
# once (12µs+14µs) by base::import at line 125 # spent 26µs making 1 call to PPIx::Regexp::Node::BEGIN@125
# spent 14µs making 1 call to warnings::unimport |
126 | 1 | 1µs | *elements = \&children; | ||
127 | } | ||||
128 | |||||
129 | =head2 find | ||||
130 | |||||
131 | my $rslt = $node->find( 'PPIx::Regexp::Token::Literal' ); | ||||
132 | my $rslt = $node->find( 'Token::Literal' ); | ||||
133 | my $rslt = $node->find( sub { | ||||
134 | return $_[1]->isa( 'PPIx::Regexp::Token::Literal' ) | ||||
135 | && $_[1]->ordinal < ord(' '); | ||||
136 | } ); | ||||
137 | |||||
138 | This method finds things. | ||||
139 | |||||
140 | If given a string as argument, it is assumed to be a class name | ||||
141 | (possibly without the leading 'PPIx::Regexp::'), and all elements of the | ||||
142 | given class are found. | ||||
143 | |||||
144 | If given a code reference, that code reference is called once for each | ||||
145 | element, and passed C<$self> and the element. The code should return | ||||
146 | true to accept the element, false to reject it, and ( for subclasses of | ||||
147 | C<PPIx::Regexp::Node>) C<undef> to prevent recursion into the node. If | ||||
148 | the code throws an exception, you get nothing back from this method. | ||||
149 | |||||
150 | Either way, the return is a reference to the list of things found, a | ||||
151 | false (but defined) value if nothing was found, or C<undef> if an error | ||||
152 | occurred. | ||||
153 | |||||
154 | =cut | ||||
155 | |||||
156 | sub _find_routine { | ||||
157 | my ( $want ) = @_; | ||||
158 | ref $want eq 'CODE' and return $want; | ||||
159 | ref $want and return; | ||||
160 | $want =~ m/ \A PPIx::Regexp:: /smx | ||||
161 | or $want = 'PPIx::Regexp::' . $want; | ||||
162 | return sub { | ||||
163 | return __instance( $_[1], $want ) ? 1 : 0; | ||||
164 | }; | ||||
165 | } | ||||
166 | |||||
167 | sub find { | ||||
168 | my ( $self, $want ) = @_; | ||||
169 | |||||
170 | $want = _find_routine( $want ) or return; | ||||
171 | |||||
172 | my @found; | ||||
173 | |||||
174 | # We use a recursion to find what we want. PPI::Node uses an | ||||
175 | # iteration. | ||||
176 | foreach my $elem ( $self->elements() ) { | ||||
177 | my $rslt = eval { $want->( $self, $elem ) } | ||||
178 | and push @found, $elem; | ||||
179 | $@ and return; | ||||
180 | |||||
181 | __instance( $elem, 'PPIx::Regexp::Node' ) or next; | ||||
182 | defined $rslt or next; | ||||
183 | $rslt = $elem->find( $want ) | ||||
184 | and push @found, @{ $rslt }; | ||||
185 | } | ||||
186 | |||||
187 | return @found ? \@found : 0; | ||||
188 | |||||
189 | } | ||||
190 | |||||
191 | =head2 find_parents | ||||
192 | |||||
193 | my $rslt = $node->find_parents( sub { | ||||
194 | return $_[1]->isa( 'PPIx::Regexp::Token::Operator' ) | ||||
195 | && $_[1]->content() eq '|'; | ||||
196 | } ); | ||||
197 | |||||
198 | This convenience method takes the same arguments as C<find>, but instead | ||||
199 | of the found objects themselves returns their parents. No parent will | ||||
200 | appear more than once in the output. | ||||
201 | |||||
202 | The return is a reference to the array of parents if any were found. If | ||||
203 | none were found the return is false but defined. If an error occurred | ||||
204 | the return is C<undef>. | ||||
205 | |||||
206 | =cut | ||||
207 | |||||
208 | sub find_parents { | ||||
209 | my ( $self, $want ) = @_; | ||||
210 | |||||
211 | my $found; | ||||
212 | $found = $self->find( $want ) or return $found; | ||||
213 | |||||
214 | my %parents; | ||||
215 | my @rslt; | ||||
216 | foreach my $elem ( @{ $found } ) { | ||||
217 | my $dad = $elem->parent() or next; | ||||
218 | $parents{ refaddr( $dad ) }++ | ||||
219 | or push @rslt, $dad; | ||||
220 | } | ||||
221 | |||||
222 | return \@rslt; | ||||
223 | } | ||||
224 | |||||
225 | =head2 find_first | ||||
226 | |||||
227 | This method has the same arguments as L</find>, but returns either a | ||||
228 | reference to the first element found, a false (but defined) value if no | ||||
229 | elements were found, or C<undef> if an error occurred. | ||||
230 | |||||
231 | =cut | ||||
232 | |||||
233 | sub find_first { | ||||
234 | my ( $self, $want ) = @_; | ||||
235 | |||||
236 | $want = _find_routine( $want ) or return; | ||||
237 | |||||
238 | # We use a recursion to find what we want. PPI::Node uses an | ||||
239 | # iteration. | ||||
240 | foreach my $elem ( $self->elements() ) { | ||||
241 | my $rslt = eval { $want->( $self, $elem ) } | ||||
242 | and return $elem; | ||||
243 | $@ and return; | ||||
244 | |||||
245 | __instance( $elem, 'PPIx::Regexp::Node' ) or next; | ||||
246 | defined $rslt or next; | ||||
247 | |||||
248 | defined( $rslt = $elem->find_first( $want ) ) | ||||
249 | or return; | ||||
250 | $rslt and return $rslt; | ||||
251 | } | ||||
252 | |||||
253 | return 0; | ||||
254 | |||||
255 | } | ||||
256 | |||||
257 | =head2 first_element | ||||
258 | |||||
259 | This method returns the first element in the node. | ||||
260 | |||||
261 | =cut | ||||
262 | |||||
263 | sub first_element { | ||||
264 | my ( $self ) = @_; | ||||
265 | return $self->{children}[0]; | ||||
266 | } | ||||
267 | |||||
268 | =head2 last_element | ||||
269 | |||||
270 | This method returns the last element in the node. | ||||
271 | |||||
272 | =cut | ||||
273 | |||||
274 | sub last_element { | ||||
275 | my ( $self ) = @_; | ||||
276 | return $self->{children}[-1]; | ||||
277 | } | ||||
278 | |||||
279 | =head2 perl_version_introduced | ||||
280 | |||||
281 | This method returns the maximum value of C<perl_version_introduced> | ||||
282 | returned by any of its elements. In other words, it returns the minimum | ||||
283 | version of Perl under which this node is valid. If there are no | ||||
284 | elements, 5.000 is returned, since that is the minimum value of Perl | ||||
285 | supported by this package. | ||||
286 | |||||
287 | =cut | ||||
288 | |||||
289 | sub perl_version_introduced { | ||||
290 | my ( $self ) = @_; | ||||
291 | return max( MINIMUM_PERL, | ||||
292 | map { $_->perl_version_introduced() } $self->elements() ); | ||||
293 | } | ||||
294 | |||||
295 | =head2 perl_version_removed | ||||
296 | |||||
297 | This method returns the minimum defined value of C<perl_version_removed> | ||||
298 | returned by any of the node's elements. In other words, it returns the | ||||
299 | lowest version of Perl in which this node is C<not> valid. If there are | ||||
300 | no elements, or if no element has a defined C<perl_version_removed>, | ||||
301 | C<undef> is returned. | ||||
302 | |||||
303 | =cut | ||||
304 | |||||
305 | sub perl_version_removed { | ||||
306 | my ( $self ) = @_; | ||||
307 | my $max; | ||||
308 | foreach my $elem ( $self->elements() ) { | ||||
309 | if ( defined ( my $ver = $elem->perl_version_removed() ) ) { | ||||
310 | if ( defined $max ) { | ||||
311 | $ver < $max and $max = $ver; | ||||
312 | } else { | ||||
313 | $max = $ver; | ||||
314 | } | ||||
315 | } | ||||
316 | } | ||||
317 | return $max; | ||||
318 | } | ||||
319 | |||||
320 | =head2 schild | ||||
321 | |||||
322 | This method returns the significant child at the given index; that is, | ||||
323 | C<< $node->schild(0) >> returns the first significant child, | ||||
324 | C<< $node->schild(1) >> returns the second significant child, and so on. | ||||
325 | Negative indices count from the end. | ||||
326 | |||||
327 | =cut | ||||
328 | |||||
329 | sub schild { | ||||
330 | my ( $self, $inx ) = @_; | ||||
331 | defined $inx or $inx = 0; | ||||
332 | |||||
333 | my $kids = $self->{children}; | ||||
334 | |||||
335 | if ( $inx >= 0 ) { | ||||
336 | |||||
337 | my $loc = 0; | ||||
338 | |||||
339 | while ( exists $kids->[$loc] ) { | ||||
340 | $kids->[$loc]->significant() or next; | ||||
341 | --$inx >= 0 and next; | ||||
342 | return $kids->[$loc]; | ||||
343 | } continue { | ||||
344 | $loc++; | ||||
345 | } | ||||
346 | |||||
347 | } else { | ||||
348 | |||||
349 | my $loc = -1; | ||||
350 | |||||
351 | while ( exists $kids->[$loc] ) { | ||||
352 | $kids->[$loc]->significant() or next; | ||||
353 | $inx++ < -1 and next; | ||||
354 | return $kids->[$loc]; | ||||
355 | } continue { | ||||
356 | --$loc; | ||||
357 | } | ||||
358 | |||||
359 | } | ||||
360 | |||||
361 | return; | ||||
362 | } | ||||
363 | |||||
364 | =head2 schildren | ||||
365 | |||||
366 | This method returns the significant children of the node. | ||||
367 | |||||
368 | =cut | ||||
369 | |||||
370 | sub schildren { | ||||
371 | my ( $self ) = @_; | ||||
372 | if ( wantarray ) { | ||||
373 | return ( grep { $_->significant() } @{ $self->{children} } ); | ||||
374 | } elsif ( defined wantarray ) { | ||||
375 | my $kids = 0; | ||||
376 | foreach ( @{ $self->{children} } ) { | ||||
377 | $_->significant() and $kids++; | ||||
378 | } | ||||
379 | return $kids; | ||||
380 | } else { | ||||
381 | return; | ||||
382 | } | ||||
383 | } | ||||
384 | |||||
385 | sub tokens { | ||||
386 | my ( $self ) = @_; | ||||
387 | return ( map { $_->tokens() } $self->elements() ); | ||||
388 | } | ||||
389 | |||||
390 | sub unescaped_content { | ||||
391 | my ( $self ) = @_; | ||||
392 | return join '', map { $_->unescaped_content() } $self->elements(); | ||||
393 | } | ||||
394 | |||||
395 | # Help for nav(); | ||||
396 | sub _nav { | ||||
397 | my ( $self, $child ) = @_; | ||||
398 | refaddr( $child->parent() ) == refaddr( $self ) | ||||
399 | or return; | ||||
400 | my ( $method, $inx ) = $child->_my_inx() | ||||
401 | or return; | ||||
402 | |||||
403 | return ( $method => [ $inx ] ); | ||||
404 | } | ||||
405 | |||||
406 | # Called by the lexer once it has done its worst to all the tokens. | ||||
407 | # Called as a method with no arguments. The return is the number of | ||||
408 | # parse failures discovered when finalizing. | ||||
409 | sub __PPIX_LEXER__finalize { | ||||
410 | my ( $self ) = @_; | ||||
411 | my $rslt = 0; | ||||
412 | foreach my $elem ( $self->elements() ) { | ||||
413 | $rslt += $elem->__PPIX_LEXER__finalize(); | ||||
414 | } | ||||
415 | return $rslt; | ||||
416 | } | ||||
417 | |||||
418 | # Called by the lexer to record the capture number. | ||||
419 | sub __PPIX_LEXER__record_capture_number { | ||||
420 | my ( $self, $number ) = @_; | ||||
421 | foreach my $kid ( $self->children() ) { | ||||
422 | $number = $kid->__PPIX_LEXER__record_capture_number( $number ); | ||||
423 | } | ||||
424 | return $number; | ||||
425 | } | ||||
426 | |||||
427 | 1 | 3µs | 1; | ||
428 | |||||
429 | __END__ |