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 65     65   404 use strict;
  65         105  
  65         1456  
6 65     65   296 use Clone ();
  65         108  
  65         667  
7 65     65   287 use Carp ();
  65         107  
  65         787  
8 65     65   255 use PPI::Token::_QuoteEngine ();
  65         111  
  65         112874  
9              
10             our $VERSION = '1.276';
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 3505     3505 0 5368 my $class = shift;
51 3505 50       6127 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 3505 50       7884 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 3505 50       9919 my $options = $QUOTES{$init} or return $self->_error(
63             "Unknown quote type '$init'"
64             );
65 3505         11278 foreach ( keys %$options ) {
66 15940         24406 $self->{$_} = $options->{$_};
67             }
68              
69             # Set up the modifiers hash if needed
70 3505 100       8680 $self->{modifiers} = {} if $self->{modifiers};
71              
72             # Handle the special < base
73 3505 100       6763 if ( $init eq '<' ) {
74 106         1011 $self->{sections}->[0] = Clone::clone( $SECTIONS{'<'} );
75             }
76              
77 3505         9089 $self;
78             }
79              
80             sub _fill {
81 3505     3505   4380 my $class = shift;
82 3505         4116 my $t = shift;
83             my $self = $t->{token}
84 3505 50       8381 or Carp::croak("::Full->_fill called without current token");
85              
86             # Load in the operator stuff if needed
87 3505 100       6614 if ( $self->{operator} ) {
88             # In an operator based quote-like, handle the gap between the
89             # operator and the opening separator.
90 2705 100       9154 if ( substr( $t->{line}, $t->{line_cursor}, 1 ) =~ /\s/ ) {
91             # Go past the gap
92 550         1576 my $gap = $self->_scan_quote_like_operator_gap( $t );
93 550 50       1034 return undef unless defined $gap;
94 550 100       1072 if ( ref $gap ) {
95             # End of file
96 185         352 $self->{content} .= $$gap;
97 185         395 return 0;
98             }
99 365         580 $self->{content} .= $gap;
100             }
101              
102             # The character we are now on is the separator. Capture,
103             # and advance into the first section.
104 2520         5135 my $sep = substr( $t->{line}, $t->{line_cursor}++, 1 );
105 2520         3918 $self->{content} .= $sep;
106              
107             # Determine if these are normal or braced type sections
108 2520 100       5188 if ( my $section = $SECTIONS{$sep} ) {
109 1090         1829 $self->{braced} = 1;
110 1090         10174 $self->{sections}->[0] = Clone::clone($section);
111             } else {
112 1430         2035 $self->{braced} = 0;
113 1430         2521 $self->{separator} = $sep;
114             }
115             }
116              
117             # Parse different based on whether we are normal or braced
118             my $rv = $self->{braced}
119 3320 100       9649 ? $self->_fill_braced($t)
120             : $self->_fill_normal($t);
121 3320 100       6883 return $rv if !$rv;
122              
123             # Return now unless it has modifiers ( i.e. s/foo//eieio )
124 2498 100       5577 return 1 unless $self->{modifiers};
125              
126             # Check for modifiers
127 1252         1545 my $char;
128 1252         1598 my $len = 0;
129 1252         6299 while ( ($char = substr( $t->{line}, $t->{line_cursor} + 1, 1 )) =~ /[^\W\d_]/ ) {
130 516         855 $len++;
131 516         799 $self->{content} .= $char;
132 516         1450 $self->{modifiers}->{lc $char} = 1;
133 516         2290 $t->{line_cursor}++;
134             }
135             }
136              
137             # Handle the content parsing path for normally separated
138             sub _fill_normal {
139 2124     2124   2658 my $self = shift;
140 2124         2855 my $t = shift;
141              
142             # Get the content up to the next separator
143 2124         5113 my $string = $self->_scan_for_unescaped_character( $t, $self->{separator} );
144 2124 50       4560 return undef unless defined $string;
145 2124 100       4419 if ( ref $string ) {
146             # End of file
147 586 100       1192 if ( length($$string) > 1 ) {
148             # Complete the properties for the first section
149 442         814 my $str = $$string;
150 442         780 chop $str;
151             $self->{sections}->[0] = {
152 442         2333 position => length($self->{content}),
153             size => length($$string) - 1,
154             type => "$self->{separator}$self->{separator}",
155             };
156 442         742 $self->{_sections} = 1;
157             } else {
158             # No sections at all
159 144         283 $self->{sections} = [ ];
160 144         214 $self->{_sections} = 0;
161             }
162 586         1039 $self->{content} .= $$string;
163 586         1022 return 0;
164             }
165              
166             # Complete the properties of the first section
167             $self->{sections}->[0] = {
168             position => length $self->{content},
169 1538         7733 size => length($string) - 1,
170             type => "$self->{separator}$self->{separator}",
171             };
172 1538         2967 $self->{content} .= $string;
173              
174             # We are done if there is only one section
175 1538 100       3763 return 1 if $self->{_sections} == 1;
176              
177             # There are two sections.
178              
179             # Advance into the next section
180 381         642 $t->{line_cursor}++;
181              
182             # Get the content up to the end separator
183 381         930 $string = $self->_scan_for_unescaped_character( $t, $self->{separator} );
184 381 50       1086 return undef unless defined $string;
185 381 100       971 if ( ref $string ) {
186             # End of file
187 69 100       237 if ( length($$string) > 1 ) {
188             # Complete the properties for the second section
189 66         128 my $str = $$string;
190 66         122 chop $str;
191             $self->{sections}->[1] = {
192 66         366 position => length($self->{content}),
193             size => length($$string) - 1,
194             type => "$self->{separator}$self->{separator}",
195             };
196             } else {
197             # No sections at all
198 3         6 $self->{_sections} = 1;
199             }
200 69         142 $self->{content} .= $$string;
201 69         138 return 0;
202             }
203              
204             # Complete the properties of the second section
205             $self->{sections}->[1] = {
206 312         1021 position => length($self->{content}),
207             size => length($string) - 1
208             };
209 312         582 $self->{content} .= $string;
210              
211 312         522 1;
212             }
213              
214             # Handle content parsing for matching brace separated
215             sub _fill_braced {
216 1196     1196   1642 my $self = shift;
217 1196         1497 my $t = shift;
218              
219             # Get the content up to the close character
220 1196         1851 my $section = $self->{sections}->[0];
221 1196         3406 my $brace_str = $self->_scan_for_brace_character( $t, $section->{_close} );
222 1196 50       2764 return undef unless defined $brace_str;
223 1196 100       2287 if ( ref $brace_str ) {
224             # End of file
225 122 100       318 if ( length($$brace_str) > 1 ) {
226             # Complete the properties for the first section
227 72         131 my $str = $$brace_str;
228 72         159 chop $str;
229             $self->{sections}->[0] = {
230             position => length($self->{content}),
231             size => length($$brace_str) - 1,
232             type => $section->{type},
233 72         346 };
234 72         150 $self->{_sections} = 1;
235             } else {
236             # No sections at all
237 50         111 $self->{sections} = [ ];
238 50         65 $self->{_sections} = 0;
239             }
240 122         235 $self->{content} .= $$brace_str;
241 122         304 return 0;
242             }
243              
244             # Complete the properties of the first section
245 1074         2188 $section->{position} = length $self->{content};
246 1074         2072 $section->{size} = length($brace_str) - 1;
247 1074         1663 $self->{content} .= $brace_str;
248 1074         1815 delete $section->{_close};
249              
250             # We are done if there is only one section
251 1074 100       2857 return 1 if $self->{_sections} == 1;
252              
253             # There are two sections.
254              
255             # Is there a gap between the sections.
256 166         358 my $char = substr( $t->{line}, ++$t->{line_cursor}, 1 );
257 166 100       506 if ( $char =~ /\s/ ) {
258             # Go past the gap
259 115         284 my $gap_str = $self->_scan_quote_like_operator_gap( $t );
260 115 50       228 return undef unless defined $gap_str;
261 115 100       203 if ( ref $gap_str ) {
262             # End of file
263 3         10 $self->{content} .= $$gap_str;
264 3         7 return 0;
265             }
266 112         193 $self->{content} .= $gap_str;
267 112         205 $char = substr( $t->{line}, $t->{line_cursor}, 1 );
268             }
269              
270 163         297 $section = $SECTIONS{$char};
271              
272 163 100       448 if ( $section ) {
    100          
273             # It's a brace
274              
275             # Initialize the second section
276 119         166 $self->{content} .= $char;
277 119         318 $section = { %$section };
278              
279             # Advance into the second section
280 119         193 $t->{line_cursor}++;
281              
282             # Get the content up to the close character
283 119         271 $brace_str = $self->_scan_for_brace_character( $t, $section->{_close} );
284 119 50       292 return undef unless defined $brace_str;
285 119 100       235 if ( ref $brace_str ) {
286             # End of file
287 9 100       29 if ( length($$brace_str) > 1 ) {
288             # Complete the properties for the second section
289 7         201 my $str = $$brace_str;
290 7         18 chop $str;
291             $self->{sections}->[1] = {
292             position => length($self->{content}),
293             size => length($$brace_str) - 1,
294             type => $section->{type},
295 7         42 };
296 7         154 $self->{_sections} = 2;
297             } else {
298             # No sections at all
299 2         5 $self->{_sections} = 1;
300             }
301 9         23 $self->{content} .= $$brace_str;
302 9         28 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 110         379 };
310 110         193 $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 25         64 $self->{content} .= $char;
317              
318             # Advance into the next section
319 25         38 $t->{line_cursor}++;
320              
321             # Get the content up to the end separator
322 25         70 my $string = $self->_scan_for_unescaped_character( $t, $char );
323 25 50       125 return undef unless defined $string;
324 25 100       84 if ( ref $string ) {
325             # End of file
326 14 100       37 if ( length($$string) > 1 ) {
327             # Complete the properties for the second section
328 6         20 my $str = $$string;
329 6         14 chop $str;
330             $self->{sections}->[1] = {
331 6         39 position => length($self->{content}),
332             size => length($$string) - 1,
333             type => "$char$char",
334             };
335             } else {
336             # Only the one section
337 8         16 $self->{_sections} = 1;
338             }
339 14         29 $self->{content} .= $$string;
340 14         44 return 0;
341             }
342              
343             # Complete the properties of the second section
344             $self->{sections}->[1] = {
345 11         72 position => length($self->{content}),
346             size => length($string) - 1,
347             type => "$char$char",
348             };
349 11         29 $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 19         122 position => length($self->{content}),
360             size => 0,
361             type => '',
362             };
363              
364             # Attach an error to the token and move on
365 19         68 $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 19         54 $t->{line_cursor}--;
369 19         40 return 0;
370             }
371              
372 121         252 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   3090 wantarray ? @{$_[0]->{sections}} : scalar @{$_[0]->{sections}}
  17         50  
  10         47  
386             }
387              
388             # Get a section's content
389             sub _section_content {
390 504     504   781 my $self = shift;
391 504         560 my $i = shift;
392 504 50       1188 $self->{sections} or return;
393 504 100       1140 my $section = $self->{sections}->[$i] or return;
394 500         1197 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   16 my $self = shift;
403 7 50       20 $self->{modifiers} or return;
404 7 100       18 wantarray and return %{ $self->{modifiers} };
  5         30  
405 2         3 return +{ %{ $self->{modifiers} } };
  2         11  
406             }
407              
408             # Get the delimiters, or at least give it a good try to get them.
409             sub _delimiters {
410 492     492   594 my $self = shift;
411 492 50       1046 $self->{sections} or return;
412 492         681 my @delims;
413 492         587 foreach my $sect ( @{ $self->{sections} } ) {
  492         905  
414 494 100       1038 if ( exists $sect->{type} ) {
415 493         963 push @delims, $sect->{type};
416             } else {
417 1         3 my $content = $self->content;
418             push @delims,
419             substr( $content, $sect->{position} - 1, 1 ) .
420 1         12 substr( $content, $sect->{position} + $sect->{size}, 1 );
421             }
422             }
423 492         1253 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