Filename | /Users/timbo/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/PPIx/Regexp/Structure.pm |
Statements | Executed 16 statements in 977µs |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 12µs | 23µs | BEGIN@45 | PPIx::Regexp::Structure::
1 | 1 | 1 | 8µs | 28µs | BEGIN@50 | PPIx::Regexp::Structure::
1 | 1 | 1 | 7µs | 11µs | BEGIN@46 | PPIx::Regexp::Structure::
1 | 1 | 1 | 7µs | 58µs | BEGIN@48 | PPIx::Regexp::Structure::
1 | 1 | 1 | 7µs | 25µs | BEGIN@51 | PPIx::Regexp::Structure::
1 | 1 | 1 | 7µs | 25µs | BEGIN@53 | PPIx::Regexp::Structure::
1 | 1 | 1 | 6µs | 24µs | BEGIN@52 | PPIx::Regexp::Structure::
0 | 0 | 0 | 0s | 0s | __error | PPIx::Regexp::Structure::
0 | 0 | 0 | 0s | 0s | _check_for_interpolated_match | PPIx::Regexp::Structure::
0 | 0 | 0 | 0s | 0s | _new | PPIx::Regexp::Structure::
0 | 0 | 0 | 0s | 0s | elements | PPIx::Regexp::Structure::
0 | 0 | 0 | 0s | 0s | finish | PPIx::Regexp::Structure::
0 | 0 | 0 | 0s | 0s | first_element | PPIx::Regexp::Structure::
0 | 0 | 0 | 0s | 0s | last_element | PPIx::Regexp::Structure::
0 | 0 | 0 | 0s | 0s | start | PPIx::Regexp::Structure::
0 | 0 | 0 | 0s | 0s | type | PPIx::Regexp::Structure::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | =head1 NAME | ||||
2 | |||||
3 | PPIx::Regexp::Structure - Represent a structure. | ||||
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::Structure> is a | ||||
13 | L<PPIx::Regexp::Node|PPIx::Regexp::Node>. | ||||
14 | |||||
15 | C<PPIx::Regexp::Structure> is the parent of | ||||
16 | L<PPIx::Regexp::Structure::Assertion|PPIx::Regexp::Structure::Assertion>, | ||||
17 | L<PPIx::Regexp::Structure::BranchReset|PPIx::Regexp::Structure::BranchReset>, | ||||
18 | L<PPIx::Regexp::Structure::Capture|PPIx::Regexp::Structure::Capture>, | ||||
19 | L<PPIx::Regexp::Structure::CharClass|PPIx::Regexp::Structure::CharClass>, | ||||
20 | L<PPIx::Regexp::Structure::Code|PPIx::Regexp::Structure::Code>, | ||||
21 | L<PPIx::Regexp::Structure::Main|PPIx::Regexp::Structure::Main>, | ||||
22 | L<PPIx::Regexp::Structure::Modifier|PPIx::Regexp::Structure::Modifier>, | ||||
23 | L<PPIx::Regexp::Structure::Quantifier|PPIx::Regexp::Structure::Quantifier>, | ||||
24 | L<PPIx::Regexp::Structure::Subexpression|PPIx::Regexp::Structure::Subexpression>, | ||||
25 | L<PPIx::Regexp::Structure::Switch|PPIx::Regexp::Structure::Switch> and | ||||
26 | L<PPIx::Regexp::Structure::Unknown|PPIx::Regexp::Structure::Unknown>. | ||||
27 | |||||
28 | =head1 DESCRIPTION | ||||
29 | |||||
30 | This class represents a bracketed construction of some sort. The | ||||
31 | brackets considered part of the structure, but not inside it. So the | ||||
32 | C<elements()> method returns the brackets if they are defined, but the | ||||
33 | C<children()> method does not. | ||||
34 | |||||
35 | =head1 METHODS | ||||
36 | |||||
37 | This class provides the following public methods. Methods not documented | ||||
38 | here are private, and unsupported in the sense that the author reserves | ||||
39 | the right to change or remove them without notice. | ||||
40 | |||||
41 | =cut | ||||
42 | |||||
43 | package PPIx::Regexp::Structure; | ||||
44 | |||||
45 | 2 | 20µs | 2 | 35µs | # spent 23µs (12+11) within PPIx::Regexp::Structure::BEGIN@45 which was called:
# once (12µs+11µs) by PPIx::Regexp::Lexer::BEGIN@44 at line 45 # spent 23µs making 1 call to PPIx::Regexp::Structure::BEGIN@45
# spent 11µs making 1 call to strict::import |
46 | 2 | 20µs | 2 | 16µs | # spent 11µs (7+4) within PPIx::Regexp::Structure::BEGIN@46 which was called:
# once (7µs+4µs) by PPIx::Regexp::Lexer::BEGIN@44 at line 46 # spent 11µs making 1 call to PPIx::Regexp::Structure::BEGIN@46
# spent 4µs making 1 call to warnings::import |
47 | |||||
48 | 2 | 24µs | 2 | 109µs | # spent 58µs (7+51) within PPIx::Regexp::Structure::BEGIN@48 which was called:
# once (7µs+51µs) by PPIx::Regexp::Lexer::BEGIN@44 at line 48 # spent 58µs making 1 call to PPIx::Regexp::Structure::BEGIN@48
# spent 51µs making 1 call to base::import |
49 | |||||
50 | 2 | 21µs | 2 | 50µs | # spent 28µs (8+21) within PPIx::Regexp::Structure::BEGIN@50 which was called:
# once (8µs+21µs) by PPIx::Regexp::Lexer::BEGIN@44 at line 50 # spent 28µs making 1 call to PPIx::Regexp::Structure::BEGIN@50
# spent 21µs making 1 call to Exporter::import |
51 | 2 | 19µs | 2 | 42µs | # spent 25µs (7+18) within PPIx::Regexp::Structure::BEGIN@51 which was called:
# once (7µs+18µs) by PPIx::Regexp::Lexer::BEGIN@44 at line 51 # spent 25µs making 1 call to PPIx::Regexp::Structure::BEGIN@51
# spent 18µs making 1 call to Exporter::import |
52 | 2 | 20µs | 2 | 41µs | # spent 24µs (6+17) within PPIx::Regexp::Structure::BEGIN@52 which was called:
# once (6µs+17µs) by PPIx::Regexp::Lexer::BEGIN@44 at line 52 # spent 24µs making 1 call to PPIx::Regexp::Structure::BEGIN@52
# spent 17µs making 1 call to Exporter::import |
53 | 2 | 850µs | 2 | 44µs | # spent 25µs (7+19) within PPIx::Regexp::Structure::BEGIN@53 which was called:
# once (7µs+19µs) by PPIx::Regexp::Lexer::BEGIN@44 at line 53 # spent 25µs making 1 call to PPIx::Regexp::Structure::BEGIN@53
# spent 18µs making 1 call to Exporter::import |
54 | |||||
55 | 1 | 700ns | our $VERSION = '0.036'; | ||
56 | |||||
57 | sub _new { | ||||
58 | my ( $class, @args ) = @_; | ||||
59 | my %brkt; | ||||
60 | if ( ref $args[0] eq 'HASH' ) { | ||||
61 | %brkt = %{ shift @args }; | ||||
62 | foreach my $key ( qw{ start type finish } ) { | ||||
63 | ref $brkt{$key} eq 'ARRAY' or $brkt{$key} = [ $brkt{$key} ]; | ||||
64 | } | ||||
65 | } else { | ||||
66 | $brkt{finish} = [ @args ? pop @args : () ]; | ||||
67 | $brkt{start} = [ @args ? shift @args : () ]; | ||||
68 | while ( @args && ! $args[0]->significant() ) { | ||||
69 | push @{ $brkt{start} }, shift @args; | ||||
70 | } | ||||
71 | $brkt{type} = []; | ||||
72 | if ( __instance( $args[0], 'PPIx::Regexp::Token::GroupType' ) ) { | ||||
73 | push @{ $brkt{type} }, shift @args; | ||||
74 | while ( @args && ! $args[0]->significant() ) { | ||||
75 | push @{ $brkt{type} }, shift @args; | ||||
76 | } | ||||
77 | } | ||||
78 | } | ||||
79 | |||||
80 | $class->_check_for_interpolated_match( \%brkt, \@args ); | ||||
81 | |||||
82 | my $self = $class->SUPER::_new( @args ) | ||||
83 | or return; | ||||
84 | |||||
85 | if ( __instance( $brkt{type}[0], 'PPIx::Regexp::Token::GroupType' ) ) { | ||||
86 | ( my $reclass = ref $brkt{type}[0] ) =~ | ||||
87 | s/ Token::GroupType /Structure/smx; | ||||
88 | $reclass->can( 'start' ) | ||||
89 | or confess "Programming error - $reclass not loaded"; | ||||
90 | bless $self, $reclass; | ||||
91 | } | ||||
92 | |||||
93 | foreach my $key ( qw{ start type finish } ) { | ||||
94 | $self->{$key} = []; | ||||
95 | ref $brkt{$key} eq 'ARRAY' | ||||
96 | or confess "Programming error - '$brkt{$key}' not an ARRAY"; | ||||
97 | foreach my $val ( @{ $brkt{$key} } ) { | ||||
98 | defined $val or next; | ||||
99 | __instance( $val, 'PPIx::Regexp::Element' ) | ||||
100 | or confess "Programming error - '$val' not a ", | ||||
101 | "PPIx::Regexp::Element"; | ||||
102 | push @{ $self->{$key} }, $val; | ||||
103 | $val->_parent( $self ); | ||||
104 | } | ||||
105 | } | ||||
106 | return $self; | ||||
107 | } | ||||
108 | |||||
109 | sub elements { | ||||
110 | my ( $self ) = @_; | ||||
111 | |||||
112 | if ( wantarray ) { | ||||
113 | return ( | ||||
114 | @{ $self->{start} }, | ||||
115 | @{ $self->{type} }, | ||||
116 | @{ $self->{children} }, | ||||
117 | @{ $self->{finish} }, | ||||
118 | ); | ||||
119 | } elsif ( defined wantarray ) { | ||||
120 | my $size = scalar @{ $self->{start} }; | ||||
121 | $size += scalar @{ $self->{type} }; | ||||
122 | $size += scalar @{ $self->{children} }; | ||||
123 | $size += scalar @{ $self->{finish} }; | ||||
124 | return $size; | ||||
125 | } else { | ||||
126 | return; | ||||
127 | } | ||||
128 | } | ||||
129 | |||||
130 | =head2 finish | ||||
131 | |||||
132 | my $elem = $struct->finish(); | ||||
133 | my @elem = $struct->finish(); | ||||
134 | my $elem = $struct->finish( 0 ); | ||||
135 | |||||
136 | Returns the finishing structure element. This is included in the | ||||
137 | C<elements> but not in the C<children>. | ||||
138 | |||||
139 | The finishing element is actually an array, though it should never have | ||||
140 | more than one element. Calling C<finish> in list context gets you all | ||||
141 | elements of the array. Calling it in scalar context gets you an element | ||||
142 | of the array, defaulting to element 0 if no argument is passed. | ||||
143 | |||||
144 | =cut | ||||
145 | |||||
146 | sub finish { | ||||
147 | my ( $self, $inx ) = @_; | ||||
148 | wantarray and return @{ $self->{finish} }; | ||||
149 | return $self->{finish}[ defined $inx ? $inx : 0 ]; | ||||
150 | } | ||||
151 | |||||
152 | sub first_element { | ||||
153 | my ( $self ) = @_; | ||||
154 | |||||
155 | $self->{start}[0] and return $self->{start}[0]; | ||||
156 | |||||
157 | $self->{type}[0] and return $self->{type}[0]; | ||||
158 | |||||
159 | if ( my $elem = $self->SUPER::first_element() ) { | ||||
160 | return $elem; | ||||
161 | } | ||||
162 | |||||
163 | $self->{finish}[0] and return $self->{finish}[0]; | ||||
164 | |||||
165 | return; | ||||
166 | } | ||||
167 | |||||
168 | sub last_element { | ||||
169 | my ( $self ) = @_; | ||||
170 | |||||
171 | $self->{finish}[-1] and return $self->{finish}[-1]; | ||||
172 | |||||
173 | if ( my $elem = $self->SUPER::last_element() ) { | ||||
174 | return $elem; | ||||
175 | } | ||||
176 | |||||
177 | $self->{type}[-1] and return $self->{type}[-1]; | ||||
178 | |||||
179 | $self->{start}[-1] and return $self->{start}[-1]; | ||||
180 | |||||
181 | return; | ||||
182 | } | ||||
183 | |||||
184 | =head2 start | ||||
185 | |||||
186 | my $elem = $struct->start(); | ||||
187 | my @elem = $struct->start(); | ||||
188 | my $elem = $struct->start( 0 ); | ||||
189 | |||||
190 | Returns the starting structure element. This is included in the | ||||
191 | C<elements> but not in the C<children>. | ||||
192 | |||||
193 | The starting element is actually an array. The first element (element 0) | ||||
194 | is the actual starting delimiter. Subsequent elements, if any, are | ||||
195 | insignificant elements (comments or white space) absorbed into the start | ||||
196 | element for ease of parsing subsequent elements. | ||||
197 | |||||
198 | Calling C<start> in list context gets you all elements of the array. | ||||
199 | Calling it in scalar context gets you an element of the array, | ||||
200 | defaulting to element 0 if no argument is passed. | ||||
201 | |||||
202 | =cut | ||||
203 | |||||
204 | sub start { | ||||
205 | my ( $self, $inx ) = @_; | ||||
206 | wantarray and return @{ $self->{start} }; | ||||
207 | return $self->{start}[ defined $inx ? $inx : 0 ]; | ||||
208 | } | ||||
209 | |||||
210 | =head2 type | ||||
211 | |||||
212 | my $elem = $struct->type(); | ||||
213 | my @elem = $struct->type(); | ||||
214 | my $elem = $struct->type( 0 ); | ||||
215 | |||||
216 | Returns the group type if any. This will be the leading | ||||
217 | L<PPIx::Regexp::Token::GroupType|PPIx::Regexp::Token::GroupType> | ||||
218 | token if any. This is included in C<elements> but not in C<children>. | ||||
219 | |||||
220 | The type is actually an array. The first element (element 0) is the | ||||
221 | actual type determiner. Subsequent elements, if any, are insignificant | ||||
222 | elements (comments or white space) absorbed into the type element for | ||||
223 | consistency with the way the start element is handled. | ||||
224 | |||||
225 | Calling C<type> in list context gets you all elements of the array. | ||||
226 | Calling it in scalar context gets you an element of the array, | ||||
227 | defaulting to element 0 if no argument is passed. | ||||
228 | |||||
229 | =cut | ||||
230 | |||||
231 | sub type { | ||||
232 | my ( $self, $inx ) = @_; | ||||
233 | wantarray and return @{ $self->{type} }; | ||||
234 | return $self->{type}[ defined $inx ? $inx : 0 ]; | ||||
235 | } | ||||
236 | |||||
237 | # Check for things like (?$foo:...) or (?$foo) | ||||
238 | sub _check_for_interpolated_match { | ||||
239 | my ( $class, $brkt, $args ) = @_; | ||||
240 | |||||
241 | # Everything we are interested in begins with a literal '?' followed | ||||
242 | # by an interpolation. | ||||
243 | __instance( $args->[0], 'PPIx::Regexp::Token::Unknown' ) | ||||
244 | and $args->[0]->content() eq '?' | ||||
245 | and __instance( $args->[1], 'PPIx::Regexp::Token::Interpolation' ) | ||||
246 | or return; | ||||
247 | |||||
248 | my $hiwater = 2; # Record how far we got into the arguments for | ||||
249 | # subsequent use detecting things like | ||||
250 | # (?$foo). | ||||
251 | |||||
252 | # If we have a literal ':' as the third argument: | ||||
253 | # GroupType::Modifier, rebless the ':' so we know not to match | ||||
254 | # against it, and splice all three tokens into the type. | ||||
255 | if ( __instance( $args->[2], 'PPIx::Regexp::Token::Literal' ) | ||||
256 | && $args->[2]->content() eq ':' ) { | ||||
257 | |||||
258 | # Rebless the '?' as a GroupType::Modifier. | ||||
259 | bless $args->[0], 'PPIx::Regexp::Token::GroupType::Modifier'; | ||||
260 | # Note that we do _not_ want __PPIX_TOKEN__post_make here. | ||||
261 | |||||
262 | # Rebless the ':' as a GroupType, just so it does not look like | ||||
263 | # something to match against. | ||||
264 | bless $args->[2], 'PPIx::Regexp::Token::GroupType'; | ||||
265 | |||||
266 | # Shove our three significant tokens into the type. | ||||
267 | push @{ $brkt->{type} }, splice @{ $args }, 0, 3; | ||||
268 | |||||
269 | # Stuff all the immediately-following insignificant tokens into | ||||
270 | # the type as well. | ||||
271 | while ( @{ $args } && ! $args->[0]->significant() ) { | ||||
272 | push @{ $brkt->{type} }, shift @{ $args }; | ||||
273 | } | ||||
274 | |||||
275 | # Return to the caller, since we have done all the damage we | ||||
276 | # can. | ||||
277 | return; | ||||
278 | } | ||||
279 | |||||
280 | # If we have a literal '-' as the third argument, we might have | ||||
281 | # something like (?$on-$off:$foo). | ||||
282 | if ( __instance( $args->[2], 'PPIx::Regexp::Token::Literal' ) | ||||
283 | && $args->[2]->content() eq '-' | ||||
284 | && __instance( $args->[3], 'PPIx::Regexp::Token::Interpolation' ) | ||||
285 | ) { | ||||
286 | $hiwater = 4; | ||||
287 | |||||
288 | if ( __instance( $args->[4], 'PPIx::Regexp::Token::Literal' ) | ||||
289 | && $args->[4]->content() eq ':' ) { | ||||
290 | |||||
291 | # Rebless the '?' as a GroupType::Modifier. | ||||
292 | bless $args->[0], 'PPIx::Regexp::Token::GroupType::Modifier'; | ||||
293 | # Note that we do _not_ want __PPIX_TOKEN__post_make here. | ||||
294 | |||||
295 | # Rebless the '-' and ':' as GroupType, just so they do not | ||||
296 | # look like something to match against. | ||||
297 | bless $args->[2], 'PPIx::Regexp::Token::GroupType'; | ||||
298 | bless $args->[4], 'PPIx::Regexp::Token::GroupType'; | ||||
299 | |||||
300 | # Shove our five significant tokens into the type. | ||||
301 | push @{ $brkt->{type} }, splice @{ $args }, 0, 5; | ||||
302 | |||||
303 | # Stuff all the immediately-following insignificant tokens | ||||
304 | # into the type as well. | ||||
305 | while ( @{ $args } && ! $args->[0]->significant() ) { | ||||
306 | push @{ $brkt->{type} }, shift @{ $args }; | ||||
307 | } | ||||
308 | |||||
309 | # Return to the caller, since we have done all the damage we | ||||
310 | # can. | ||||
311 | return; | ||||
312 | } | ||||
313 | } | ||||
314 | |||||
315 | # If the group contains _any_ significant tokens at this point, we | ||||
316 | # do _not_ have something like (?$foo). | ||||
317 | foreach my $inx ( $hiwater .. $#$args ) { | ||||
318 | $args->[$inx]->significant() and return; | ||||
319 | } | ||||
320 | |||||
321 | # Rebless the '?' as a GroupType::Modifier. | ||||
322 | bless $args->[0], 'PPIx::Regexp::Token::GroupType::Modifier'; | ||||
323 | # Note that we do _not_ want __PPIX_TOKEN__post_make here. | ||||
324 | |||||
325 | # Shove all the contents of $args into type, using splice to leave | ||||
326 | # @{ $args } empty after we do this. | ||||
327 | push @{ $brkt->{type} }, splice @{ $args }; | ||||
328 | |||||
329 | # We have done all the damage we can. | ||||
330 | return; | ||||
331 | } | ||||
332 | |||||
333 | sub __error { | ||||
334 | my ( $self, $msg ) = @_; | ||||
335 | defined $msg | ||||
336 | or $msg = 'Was class ' . ref $self; | ||||
337 | $self->{error} = $msg; | ||||
338 | bless $self, STRUCTURE_UNKNOWN; | ||||
339 | return 1; | ||||
340 | } | ||||
341 | |||||
342 | 1 | 2µs | 1; | ||
343 | |||||
344 | __END__ |