| 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 | PPIx::Regexp::Structure::BEGIN@45 |
| 1 | 1 | 1 | 8µs | 28µs | PPIx::Regexp::Structure::BEGIN@50 |
| 1 | 1 | 1 | 7µs | 11µs | PPIx::Regexp::Structure::BEGIN@46 |
| 1 | 1 | 1 | 7µs | 58µs | PPIx::Regexp::Structure::BEGIN@48 |
| 1 | 1 | 1 | 7µs | 25µs | PPIx::Regexp::Structure::BEGIN@51 |
| 1 | 1 | 1 | 7µs | 25µs | PPIx::Regexp::Structure::BEGIN@53 |
| 1 | 1 | 1 | 6µs | 24µs | PPIx::Regexp::Structure::BEGIN@52 |
| 0 | 0 | 0 | 0s | 0s | PPIx::Regexp::Structure::__error |
| 0 | 0 | 0 | 0s | 0s | PPIx::Regexp::Structure::_check_for_interpolated_match |
| 0 | 0 | 0 | 0s | 0s | PPIx::Regexp::Structure::_new |
| 0 | 0 | 0 | 0s | 0s | PPIx::Regexp::Structure::elements |
| 0 | 0 | 0 | 0s | 0s | PPIx::Regexp::Structure::finish |
| 0 | 0 | 0 | 0s | 0s | PPIx::Regexp::Structure::first_element |
| 0 | 0 | 0 | 0s | 0s | PPIx::Regexp::Structure::last_element |
| 0 | 0 | 0 | 0s | 0s | PPIx::Regexp::Structure::start |
| 0 | 0 | 0 | 0s | 0s | PPIx::Regexp::Structure::type |
| 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__ |