File Coverage

blib/lib/PPI/Token/_QuoteEngine/Full.pm
Criterion Covered Total %
statement 171 171 100.0
branch 72 86 83.7
condition n/a
subroutine 12 12 100.0
pod 0 1 0.0
total 255 270 94.4


line stmt bran cond sub pod time code
1             package PPI::Token::_QuoteEngine::Full;
2              
3             # Full quote engine
4              
5 64     64   351 use strict;
  64         122  
  64         1418  
6 64     64   271 use Clone ();
  64         106  
  64         621  
7 64     64   229 use Carp ();
  64         99  
  64         760  
8 64     64   245 use PPI::Token::_QuoteEngine ();
  64         108  
  64         110214  
9              
10             our $VERSION = '1.275';
11              
12             our @ISA = 'PPI::Token::_QuoteEngine';
13              
14             # Prototypes for the different braced sections
15             my %SECTIONS = (
16             '(' => { type => '()', _close => ')' },
17             '<' => { type => '<>', _close => '>' },
18             '[' => { type => '[]', _close => ']' },
19             '{' => { type => '{}', _close => '}' },
20             );
21              
22             # For each quote type, the extra fields that should be set.
23             # This should give us faster initialization.
24             my %QUOTES = (
25             'q' => { operator => 'q', braced => undef, separator => undef, _sections => 1 },
26             'qq' => { operator => 'qq', braced => undef, separator => undef, _sections => 1 },
27             'qx' => { operator => 'qx', braced => undef, separator => undef, _sections => 1 },
28             'qw' => { operator => 'qw', braced => undef, separator => undef, _sections => 1 },
29             'qr' => { operator => 'qr', braced => undef, separator => undef, _sections => 1, modifiers => 1 },
30             'm' => { operator => 'm', braced => undef, separator => undef, _sections => 1, modifiers => 1 },
31             's' => { operator => 's', braced => undef, separator => undef, _sections => 2, modifiers => 1 },
32             'tr' => { operator => 'tr', braced => undef, separator => undef, _sections => 2, modifiers => 1 },
33              
34             # Y is the little-used variant of tr
35             'y' => { operator => 'y', braced => undef, separator => undef, _sections => 2, modifiers => 1 },
36              
37             '/' => { operator => undef, braced => 0, separator => '/', _sections => 1, modifiers => 1 },
38              
39             # Angle brackets quotes mean "readline(*FILEHANDLE)"
40             '<' => { operator => undef, braced => 1, separator => undef, _sections => 1, },
41              
42             # The final ( and kind of depreciated ) "first match only" one is not
43             # used yet, since I'm not sure on the context differences between
44             # this and the trinary operator, but it's here for completeness.
45             '?' => { operator => undef, braced => 0, separator => '?', _sections => 1, modifiers => 1 },
46             );
47              
48              
49             sub new {
50 3466     3466 0 5105 my $class = shift;
51 3466 50       6190 my $init = defined $_[0]
52             ? shift
53             : Carp::croak("::Full->new called without init string");
54              
55             # Create the token
56             ### This manual SUPER'ing ONLY works because none of
57             ### Token::Quote, Token::QuoteLike and Token::Regexp
58             ### implement a new function of their own.
59 3466 50       7945 my $self = PPI::Token::new( $class, $init ) or return undef;
60              
61             # Do we have a prototype for the initializer? If so, add the extra fields
62 3466 50       9066 my $options = $QUOTES{$init} or return $self->_error(
63             "Unknown quote type '$init'"
64             );
65 3466         10915 foreach ( keys %$options ) {
66 15735         24443 $self->{$_} = $options->{$_};
67             }
68              
69             # Set up the modifiers hash if needed
70 3466 100       8087 $self->{modifiers} = {} if $self->{modifiers};
71              
72             # Handle the special < base
73 3466 100       6396 if ( $init eq '<' ) {
74 111         1091 $self->{sections}->[0] = Clone::clone( $SECTIONS{'<'} );
75             }
76              
77 3466         8323 $self;
78             }
79              
80             sub _fill {
81 3466     3466   4286 my $class = shift;
82 3466         4039 my $t = shift;
83             my $self = $t->{token}
84 3466 50       8067 or Carp::croak("::Full->_fill called without current token");
85              
86             # Load in the operator stuff if needed
87 3466 100       6179 if ( $self->{operator} ) {
88             # In an operator based quote-like, handle the gap between the
89             # operator and the opening separator.
90 2684 100       8684 if ( substr( $t->{line}, $t->{line_cursor}, 1 ) =~ /\s/ ) {
91             # Go past the gap
92 535         1611 my $gap = $self->_scan_quote_like_operator_gap( $t );
93 535 50       1020 return undef unless defined $gap;
94 535 100       980 if ( ref $gap ) {
95             # End of file
96 182         293 $self->{content} .= $$gap;
97 182         370 return 0;
98             }
99 353         564 $self->{content} .= $gap;
100             }
101              
102             # The character we are now on is the separator. Capture,
103             # and advance into the first section.
104 2502         4729 my $sep = substr( $t->{line}, $t->{line_cursor}++, 1 );
105 2502         3692 $self->{content} .= $sep;
106              
107             # Determine if these are normal or braced type sections
108 2502 100       4787 if ( my $section = $SECTIONS{$sep} ) {
109 1110         1807 $self->{braced} = 1;
110 1110         10078 $self->{sections}->[0] = Clone::clone($section);
111             } else {
112 1392         1800 $self->{braced} = 0;
113 1392         2356 $self->{separator} = $sep;
114             }
115             }
116              
117             # Parse different based on whether we are normal or braced
118             my $rv = $self->{braced}
119 3284 100       9036 ? $self->_fill_braced($t)
120             : $self->_fill_normal($t);
121 3284 100       7092 return $rv if !$rv;
122              
123             # Return now unless it has modifiers ( i.e. s/foo//eieio )
124 2440 100       5351 return 1 unless $self->{modifiers};
125              
126             # Check for modifiers
127 1185         1557 my $char;
128 1185         1585 my $len = 0;
129 1185         5650 while ( ($char = substr( $t->{line}, $t->{line_cursor} + 1, 1 )) =~ /[^\W\d_]/ ) {
130 453         708 $len++;
131 453         629 $self->{content} .= $char;
132 453         1178 $self->{modifiers}->{lc $char} = 1;
133 453         1989 $t->{line_cursor}++;
134             }
135             }
136              
137             # Handle the content parsing path for normally separated
138             sub _fill_normal {
139 2063     2063   2496 my $self = shift;
140 2063         2360 my $t = shift;
141              
142             # Get the content up to the next separator
143 2063         4640 my $string = $self->_scan_for_unescaped_character( $t, $self->{separator} );
144 2063 50       4214 return undef unless defined $string;
145 2063 100       3925 if ( ref $string ) {
146             # End of file
147 582 100       1053 if ( length($$string) > 1 ) {
148             # Complete the properties for the first section
149 435         684 my $str = $$string;
150 435         604 chop $str;
151             $self->{sections}->[0] = {
152 435         2034 position => length($self->{content}),
153             size => length($$string) - 1,
154             type => "$self->{separator}$self->{separator}",
155             };
156 435         717 $self->{_sections} = 1;
157             } else {
158             # No sections at all
159 147         261 $self->{sections} = [ ];
160 147         216 $self->{_sections} = 0;
161             }
162 582         913 $self->{content} .= $$string;
163 582         1116 return 0;
164             }
165              
166             # Complete the properties of the first section
167             $self->{sections}->[0] = {
168             position => length $self->{content},
169 1481         7276 size => length($string) - 1,
170             type => "$self->{separator}$self->{separator}",
171             };
172 1481         2736 $self->{content} .= $string;
173              
174             # We are done if there is only one section
175 1481 100       3483 return 1 if $self->{_sections} == 1;
176              
177             # There are two sections.
178              
179             # Advance into the next section
180 367         576 $t->{line_cursor}++;
181              
182             # Get the content up to the end separator
183 367         907 $string = $self->_scan_for_unescaped_character( $t, $self->{separator} );
184 367 50       1001 return undef unless defined $string;
185 367 100       842 if ( ref $string ) {
186             # End of file
187 72 100       271 if ( length($$string) > 1 ) {
188             # Complete the properties for the second section
189 70         161 my $str = $$string;
190 70         111 chop $str;
191             $self->{sections}->[1] = {
192 70         364 position => length($self->{content}),
193             size => length($$string) - 1,
194             type => "$self->{separator}$self->{separator}",
195             };
196             } else {
197             # No sections at all
198 2         7 $self->{_sections} = 1;
199             }
200 72         167 $self->{content} .= $$string;
201 72         132 return 0;
202             }
203              
204             # Complete the properties of the second section
205             $self->{sections}->[1] = {
206 295         963 position => length($self->{content}),
207             size => length($string) - 1
208             };
209 295         520 $self->{content} .= $string;
210              
211 295         472 1;
212             }
213              
214             # Handle content parsing for matching brace separated
215             sub _fill_braced {
216 1221     1221   1788 my $self = shift;
217 1221         1456 my $t = shift;
218              
219             # Get the content up to the close character
220 1221         1855 my $section = $self->{sections}->[0];
221 1221         3224 my $brace_str = $self->_scan_for_brace_character( $t, $section->{_close} );
222 1221 50       2544 return undef unless defined $brace_str;
223 1221 100       2319 if ( ref $brace_str ) {
224             # End of file
225 150 100       344 if ( length($$brace_str) > 1 ) {
226             # Complete the properties for the first section
227 100         162 my $str = $$brace_str;
228 100         206 chop $str;
229             $self->{sections}->[0] = {
230             position => length($self->{content}),
231             size => length($$brace_str) - 1,
232             type => $section->{type},
233 100         473 };
234 100         174 $self->{_sections} = 1;
235             } else {
236             # No sections at all
237 50         139 $self->{sections} = [ ];
238 50         99 $self->{_sections} = 0;
239             }
240 150         273 $self->{content} .= $$brace_str;
241 150         357 return 0;
242             }
243              
244             # Complete the properties of the first section
245 1071         2014 $section->{position} = length $self->{content};
246 1071         2009 $section->{size} = length($brace_str) - 1;
247 1071         1793 $self->{content} .= $brace_str;
248 1071         1783 delete $section->{_close};
249              
250             # We are done if there is only one section
251 1071 100       2765 return 1 if $self->{_sections} == 1;
252              
253             # There are two sections.
254              
255             # Is there a gap between the sections.
256 164         329 my $char = substr( $t->{line}, ++$t->{line_cursor}, 1 );
257 164 100       486 if ( $char =~ /\s/ ) {
258             # Go past the gap
259 118         279 my $gap_str = $self->_scan_quote_like_operator_gap( $t );
260 118 50       240 return undef unless defined $gap_str;
261 118 100       222 if ( ref $gap_str ) {
262             # End of file
263 2         4 $self->{content} .= $$gap_str;
264 2         5 return 0;
265             }
266 116         189 $self->{content} .= $gap_str;
267 116         255 $char = substr( $t->{line}, $t->{line_cursor}, 1 );
268             }
269              
270 162         259 $section = $SECTIONS{$char};
271              
272 162 100       465 if ( $section ) {
    100          
273             # It's a brace
274              
275             # Initialize the second section
276 119         168 $self->{content} .= $char;
277 119         338 $section = { %$section };
278              
279             # Advance into the second section
280 119         182 $t->{line_cursor}++;
281              
282             # Get the content up to the close character
283 119         279 $brace_str = $self->_scan_for_brace_character( $t, $section->{_close} );
284 119 50       246 return undef unless defined $brace_str;
285 119 100       206 if ( ref $brace_str ) {
286             # End of file
287 6 100       15 if ( length($$brace_str) > 1 ) {
288             # Complete the properties for the second section
289 4         191 my $str = $$brace_str;
290 4         9 chop $str;
291             $self->{sections}->[1] = {
292             position => length($self->{content}),
293             size => length($$brace_str) - 1,
294             type => $section->{type},
295 4         17 };
296 4         120 $self->{_sections} = 2;
297             } else {
298             # No sections at all
299 2         6 $self->{_sections} = 1;
300             }
301 6         15 $self->{content} .= $$brace_str;
302 6         16 return 0;
303             } else {
304             # Complete the properties for the second section
305             $self->{sections}->[1] = {
306             position => length($self->{content}),
307             size => length($brace_str) - 1,
308             type => $section->{type},
309 113         360 };
310 113         192 $self->{content} .= $brace_str;
311             }
312             } elsif ( $char =~ m/ \A [^\w\s] \z /smx ) {
313             # It is some other delimiter (weird, but possible)
314              
315             # Add the delimiter to the content.
316 28         59 $self->{content} .= $char;
317              
318             # Advance into the next section
319 28         48 $t->{line_cursor}++;
320              
321             # Get the content up to the end separator
322 28         82 my $string = $self->_scan_for_unescaped_character( $t, $char );
323 28 50       102 return undef unless defined $string;
324 28 100       79 if ( ref $string ) {
325             # End of file
326 17 100       66 if ( length($$string) > 1 ) {
327             # Complete the properties for the second section
328 8         20 my $str = $$string;
329 8         19 chop $str;
330             $self->{sections}->[1] = {
331 8         48 position => length($self->{content}),
332             size => length($$string) - 1,
333             type => "$char$char",
334             };
335             } else {
336             # Only the one section
337 9         17 $self->{_sections} = 1;
338             }
339 17         39 $self->{content} .= $$string;
340 17         37 return 0;
341             }
342              
343             # Complete the properties of the second section
344             $self->{sections}->[1] = {
345 11         62 position => length($self->{content}),
346             size => length($string) - 1,
347             type => "$char$char",
348             };
349 11         33 $self->{content} .= $string;
350              
351             } else {
352              
353             # Error, it has to be a delimiter of some sort.
354             # Although this will result in a REALLY illegal regexp,
355             # we allow it anyway.
356              
357             # Create a null second section
358             $self->{sections}->[1] = {
359 15         64 position => length($self->{content}),
360             size => 0,
361             type => '',
362             };
363              
364             # Attach an error to the token and move on
365 15         45 $self->{_error} = "No second section of regexp, or does not start with a balanced character";
366              
367             # Roll back the cursor one char and return signalling end of regexp
368 15         28 $t->{line_cursor}--;
369 15         32 return 0;
370             }
371              
372 124         262 1;
373             }
374              
375              
376              
377              
378              
379             #####################################################################
380             # Additional methods to find out about the quote
381              
382             # In a scalar context, get the number of sections
383             # In an array context, get the section information
384             sub _sections {
385 27 100   27   3108 wantarray ? @{$_[0]->{sections}} : scalar @{$_[0]->{sections}}
  17         50  
  10         45  
386             }
387              
388             # Get a section's content
389             sub _section_content {
390 504     504   830 my $self = shift;
391 504         605 my $i = shift;
392 504 50       1250 $self->{sections} or return;
393 504 100       1057 my $section = $self->{sections}->[$i] or return;
394 500         1206 return substr( $self->content, $section->{position}, $section->{size} );
395             }
396              
397             # Get the modifiers if any.
398             # In list context, return the modifier hash.
399             # In scalar context, clone the hash and return a reference to it.
400             # If there are no modifiers, simply return.
401             sub _modifiers {
402 7     7   14 my $self = shift;
403 7 50       22 $self->{modifiers} or return;
404 7 100       19 wantarray and return %{ $self->{modifiers} };
  5         33  
405 2         4 return +{ %{ $self->{modifiers} } };
  2         12  
406             }
407              
408             # Get the delimiters, or at least give it a good try to get them.
409             sub _delimiters {
410 492     492   637 my $self = shift;
411 492 50       882 $self->{sections} or return;
412 492         709 my @delims;
413 492         571 foreach my $sect ( @{ $self->{sections} } ) {
  492         972  
414 494 100       963 if ( exists $sect->{type} ) {
415 493         972 push @delims, $sect->{type};
416             } else {
417 1         4 my $content = $self->content;
418             push @delims,
419             substr( $content, $sect->{position} - 1, 1 ) .
420 1         5 substr( $content, $sect->{position} + $sect->{size}, 1 );
421             }
422             }
423 492         1260 return @delims;
424             }
425              
426             1;
427              
428             =pod
429              
430             =head1 SUPPORT
431              
432             See the L in the main module.
433              
434             =head1 AUTHOR
435              
436             Adam Kennedy Eadamk@cpan.orgE
437              
438             =head1 COPYRIGHT
439              
440             Copyright 2001 - 2011 Adam Kennedy.
441              
442             This program is free software; you can redistribute
443             it and/or modify it under the same terms as Perl itself.
444              
445             The full text of the license can be found in the
446             LICENSE file included with this module.
447              
448             =cut