File Coverage

lib/Perl/PrereqScanner/NotQuiteLite.pm
Criterion Covered Total %
statement 1277 1461 87.4
branch 763 930 82.0
condition 284 397 71.5
subroutine 30 33 90.9
pod 3 3 100.0
total 2357 2824 83.4


line stmt bran cond sub pod time code
1             package Perl::PrereqScanner::NotQuiteLite;
2              
3 102     102   8347965 use strict;
  102         186  
  102         3349  
4 102     102   432 use warnings;
  102         161  
  102         3654  
5 102     102   461 use Carp;
  102         167  
  102         5364  
6 102     102   44250 use Perl::PrereqScanner::NotQuiteLite::Context;
  102         3559  
  102         7337  
7 102     102   2096 use Perl::PrereqScanner::NotQuiteLite::Util;
  102         1694  
  102         14780  
8              
9             our $VERSION = '0.9918';
10              
11             our @BUNDLED_PARSERS = qw/
12             Aliased AnyMoose Autouse Catalyst ClassAccessor
13             ClassAutouse ClassLoad Core FeatureCompatClass Inline KeywordDeclare Later
14             Mixin ModuleRuntime MojoBase Moose MooseXDeclare ObjectPad Only
15             PackageVariant Plack POE Prefork Superclass Syntax SyntaxCollector
16             TestClassMost TestMore TestRequires UniversalVersion Unless
17             /;
18             our @DEFAULT_PARSERS = qw/Core Moose/;
19              
20             ### Helpers For Debugging
21              
22 102   50 102   519 use constant DEBUG => !!$ENV{PERL_PSNQL_DEBUG} || 0;
  102         1615  
  102         14500  
23 102     102   2055 use constant DEBUG_RE => DEBUG > 3 ? 1 : 0;
  102         133  
  102         11295  
24              
25       0     sub _debug {}
26       1     sub _error {}
27       0     sub _dump_stack {}
28              
29             if (DEBUG) {
30             require Data::Dump; Data::Dump->import(qw/dump/);
31 102     102   505 no warnings 'redefine';
  102         169  
  102         1870190  
32             *_debug = sub { print @_, "\n" };
33             *_error = sub { print @_, "*" x 50, "\n" };
34             *_dump_stack = sub {
35             my ($c, $char) = @_;
36             my $stacked = join '', map {($_->[2] ? "($_->[2])" : '').$_->[0]} @{$c->{stack}};
37             _debug("$char \t\t\t\t stacked: $stacked");
38             };
39             }
40              
41             sub _match_error {
42 5     5   7 my $rstr = shift;
43 5         15 $@ = shift() . substr($$rstr, pos($$rstr), 100);
44 5         22 return;
45             }
46              
47             ### Global Variables To Be Sorted Out Later
48              
49             my %unsupported_packages = map {$_ => 1} qw(
50             );
51              
52             my %sub_keywords = (
53             'Function::Parameters' => [qw/fun method/],
54             'TryCatch' => [qw/try catch/],
55             );
56              
57             my %filter_modules = (
58             tt => sub { ${$_[0]} =~ s|\G.+?no\s*tt\s*;||s; 0; },
59             'Text::RewriteRules' => sub { ${$_[0]} =~ s|RULES.+?ENDRULES\n||gs; 1 },
60             );
61              
62             my %is_conditional = map {$_ => 1} qw(
63             if elsif unless else given when
64             for foreach while until
65             );
66              
67             my %ends_expr = map {$_ => 1} qw(
68             and or xor
69             if else elsif unless when default
70             for foreach while until
71             && || !~ =~ = += -= *= /= **= //= %= ^= |=
72             > < >= <= <> <=> cmp ge gt le lt eq ne ? :
73             );
74              
75             my %has_sideff = map {$_ => 1} qw(
76             and or xor && || //
77             if unless when
78             );
79              
80             # keywords that allow /regexp/ to follow directly
81             my %regexp_may_follow = map {$_ => 1} qw(
82             and or cmp if elsif unless eq ne
83             gt lt ge le for while until grep map not split when
84             return
85             );
86              
87             my $re_namespace = qr/(?:::|')?(?:[a-zA-Z0-9_]+(?:(?:::|')[a-zA-Z0-9_]+)*)/;
88             my $re_nonblock_chars = qr/[^\\\(\)\{\}\[\]\<\>\/"'`#q~,\s]*/;
89             my $re_variable = qr/
90             (?:$re_namespace)
91             | (?:\^[A-Z\]])
92             | (?:\{\^[A-Z0-9_]+\})
93             | (?:[_"\(\)<\\\&`'\+\-,.\/\%#:=~\|?!\@\*\[\]\^])
94             /x;
95             my $re_pod = qr/(
96             =[a-zA-Z]\w*\b
97             .*?
98             (?:(?:\n)
99             =cut\b.*?(?:\n|\z)|\z)
100             )/sx;
101             my $re_comment = qr/(?:\s*#[^\n]*?\n)*(?:\s*#[^\n]*?)(?:\n|$)/s;
102              
103             my $g_re_scalar_variable = qr{\G(\$(?:$re_variable))};
104             my $g_re_hash_shortcut = qr{\G(\{\s*(?:[\+\-]?\w+|(['"])[\w\s]+\2|(?:$re_nonblock_chars))\s*(?
105             my $g_re_prototype = qr{\G(\([^\)]*?\))};
106              
107             my %ReStrInDelims;
108             sub _gen_re_str_in_delims {
109 339     339   579 my $delim = shift;
110 339   66     1155 $ReStrInDelims{$delim} ||= do {
111 338 100       766 if ($delim eq '\\') {
112 2         12 qr/(?:[^\\]*(?:(?:\\\\)[^\\]*)*)/s;
113             } else {
114 336         585 $delim = quotemeta $delim;
115 336         10553 qr/(?:[^\\$delim]*(?:\\.[^\\$delim]*)*)/s;
116             }
117             };
118             }
119              
120             my $re_str_in_single_quotes = _gen_re_str_in_delims(q{'});
121             my $re_str_in_double_quotes = _gen_re_str_in_delims(q{"});
122             my $re_str_in_backticks = _gen_re_str_in_delims(q{`});
123              
124             my %ReStrInDelimsWithEndDelim;
125             sub _gen_re_str_in_delims_with_end_delim {
126 96     96   166 my $delim = shift;
127 96   66     327 $ReStrInDelimsWithEndDelim{$delim} ||= do {
128 33         149 my $re = _gen_re_str_in_delims($delim);
129 33         1235 qr{$re\Q$delim\E};
130             };
131             }
132              
133             my %RdelSkip;
134             sub _gen_rdel_and_re_skip {
135 164     164   255 my $ldel = shift;
136 164   66     229 @{$RdelSkip{$ldel} ||= do {
  164         630  
137 40         134 (my $rdel = $ldel) =~ tr/[({/;
138 40         946 my $re_skip = qr{[^\Q$ldel$rdel\E\\]+};
139 40         248 [$rdel, $re_skip];
140             }};
141             }
142              
143             my %RegexpShortcut;
144             sub _gen_re_regexp_shortcut {
145 198     198   440 my ($ldel, $rdel) = @_;
146 198   66     592 $RegexpShortcut{$ldel} ||= do {
147 28         62 $ldel = quotemeta $ldel;
148 28 100       80 $rdel = $rdel ? quotemeta $rdel : $ldel;
149 28         1769 qr{(?:[^\\\(\)\{\}\[\]<>$ldel$rdel]*(?:\\.[^\\\(\)\[\]\{\}<>$ldel$rdel]*)*)$rdel};
150             };
151             }
152              
153             ############################
154              
155             my %LOADED;
156              
157             sub new {
158 781     781 1 13940919 my ($class, %args) = @_;
159              
160 781         1862 my %mapping;
161 781         2964 my @parsers = $class->_get_parsers($args{parsers});
162 781         1591 for my $parser (@parsers) {
163 24009 100       42693 if (!exists $LOADED{$parser}) {
164 2889         165882 eval "require $parser; 1";
165 2889 50       14772 if (my $error = $@) {
166 0 0       0 $parser->can('register') or die "Parser Error: $error";
167             }
168 2889 50       41851 $LOADED{$parser} = $parser->can('register') ? $parser->register(%args) : undef;
169             }
170 24009 50       43713 my $parser_mapping = $LOADED{$parser} or next;
171 24009         30827 for my $type (qw/use no keyword method/) {
172 96036 100       147053 next unless exists $parser_mapping->{$type};
173 26343         29251 for my $name (keys %{$parser_mapping->{$type}}) {
  26343         57950  
174             $mapping{$type}{$name} = [
175             $parser,
176 136933 100 100     389002 $parser_mapping->{$type}{$name},
177             (($type eq 'use' or $type eq 'no') ? ($name) : ()),
178             ];
179             }
180             }
181 24009 100       95747 if ($parser->can('register_fqfn')) {
182 2325         6531 my $fqfn_mapping = $parser->register_fqfn;
183 2325         5128 for my $name (keys %$fqfn_mapping) {
184 6972         21512 my ($module) = $name =~ /^(.+)::/;
185             $mapping{keyword}{$name} = [
186             $parser,
187 6972         19612 $fqfn_mapping->{$name},
188             $module,
189             ];
190             }
191             }
192             }
193 781         1693 $args{_} = \%mapping;
194              
195 781         4581 bless \%args, $class;
196             }
197              
198             sub _get_parsers {
199 781     781   1761 my ($class, $list) = @_;
200 781         1408 my @parsers;
201             my %should_ignore;
202 781 50       1281 for my $parser (@{$list || [qw/:default/]}) {
  781         2599  
203 786 50       2553 if ($parser eq ':installed') {
    100          
    100          
    100          
    100          
    100          
204 0         0 require Module::Find;
205 0         0 push @parsers, Module::Find::findsubmod("$class\::Parser");
206             } elsif ($parser eq ':bundled') {
207 774         2083 push @parsers, map {"$class\::Parser::$_"} @BUNDLED_PARSERS;
  23994         40661  
208             } elsif ($parser eq ':default') {
209 5         14 push @parsers, map {"$class\::Parser::$_"} @DEFAULT_PARSERS;
  10         32  
210             } elsif ($parser =~ s/^\+//) {
211 1         3 push @parsers, $parser;
212             } elsif ($parser =~ s/^\-//) {
213 1         4 $should_ignore{"$class\::Parser\::$parser"} = 1;
214             } elsif ($parser =~ /^$class\::Parser::/) {
215 1         2 push @parsers, $parser;
216             } else {
217 4         17 push @parsers, "$class\::Parser\::$parser";
218             }
219             }
220 781         1580 grep {!$should_ignore{$_}} @parsers;
  24010         33604  
221             }
222              
223             sub scan_file {
224 83     83 1 187 my ($self, $file) = @_;
225 83         102 _debug("START SCANNING $file") if DEBUG;
226 83 50       236 print STDERR " Scanning $file\n" if $self->{verbose};
227 83 50       3353 open my $fh, '<', $file or croak "Can't open $file: $!";
228 83         158 my $code = do { local $/; <$fh> };
  83         364  
  83         2663  
229 83         276 $self->{file} = $file;
230 83         245 $self->scan_string($code);
231             }
232              
233             sub scan_string {
234 781     781 1 4163 my ($self, $string) = @_;
235              
236 781 50       1711 $string = '' unless defined $string;
237              
238 781         4546 my $c = Perl::PrereqScanner::NotQuiteLite::Context->new(%$self);
239              
240 781 50       2391 if ($self->{quick}) {
241 0         0 $c->{file_size} = length $string;
242 0 0       0 $self->_skim_string($c, \$string) if $c->{file_size} > 30_000;
243             }
244              
245             # UTF8 BOM
246 781 50       2393 if ($string =~ s/\A(\xef\xbb\xbf)//s) {
247 0         0 utf8::decode($string);
248 0         0 $c->{decoded} = 1;
249             }
250             # Other BOMs (TODO: also decode?)
251 781         2068 $string =~ s/\A(\x00\x00\xfe\xff|\xff\xfe\x00\x00|\xfe\xff|\xff\xfe)//s;
252              
253             # normalize
254 781         1105 if ("\n" eq "\015") {
255             $string =~ s/(?:\015?\012)/\n/gs;
256             } elsif ("\n" eq "\012") {
257 781         1559 $string =~ s/(?:\015\012?)/\n/gs;
258             } elsif ("\n" eq "\015\012") {
259             $string =~ s/(?:\015(?!\012)|(?
260             } else {
261             $string =~ s/(?:\015\012|\015|\012)/\n/gs;
262             }
263 781         12668 $string =~ s/[ \t]+/ /g;
264 781         16770 $string =~ s/(?: *\n)+/\n/gs;
265              
266             # FIXME
267 781         2396 $c->{stack} = [];
268 781         1827 $c->{errors} = [];
269             $c->{callback} = {
270 781         3484 use => \&_use,
271             require => \&_require,
272             no => \&_no,
273             };
274 781         1587 $c->{wants_doc} = 0;
275              
276 781         2478 pos($string) = 0;
277              
278             {
279 781         1484 local $@;
  790         1182  
280 790         1661 eval { $self->_scan($c, \$string, 0) };
  790         2951  
281 790 50       1644 push @{$c->{errors}}, "Scan Error: $@" if $@;
  0         0  
282 790 100       2133 if ($c->{redo}) {
283 9         21 delete $c->{redo};
284 9         13 delete $c->{ended};
285 9         12 @{$c->{stack}} = ();
  9         18  
286 9         15 redo;
287             }
288             }
289              
290 781 100 66     1113 if (@{$c->{stack}} and !$c->{quick}) {
  781         2140  
291 1         587 require Data::Dump;
292 1         4711 push @{$c->{errors}}, Data::Dump::dump($c->{stack});
  1         6  
293             }
294              
295 781         15171 $c->remove_inner_packages_from_requirements;
296 781         2892 $c->merge_perl;
297              
298 781         9313 $c;
299             }
300              
301             sub _skim_string {
302 0     0   0 my ($self, $c, $rstr) = @_;
303 0   0     0 my $pos = pos($$rstr) || 0;
304 0         0 my $last_found = 0;
305 0         0 my $saw_moose;
306 0         0 my $re = qr/\G.*?\b((?:use|require|no)\s+(?:[A-Za-z][A-Za-z0-9_]*::)*[A-Za-z][A-Za-z0-9_]*)/;
307 0         0 while(my ($match) = $$rstr =~ /$re/gc) {
308 0         0 $last_found = pos($$rstr) + length $match;
309 0 0 0     0 if (!$saw_moose and $match =~ /^use\s+(?:Mo(?:o|(?:[ou]se))?X?|MooseX::Declare)\b/) {
310 0         0 $re = qr/\G.*?\b((?:(?:use|require|no)\s+(?:[A-Za-z][A-Za-z0-9_]*::)*[A-Za-z][A-Za-z0-9_]*)|(?:(?:extends|with)\s+(?:["']|q[a-z]*[^a-zA-Z0-9_])(?:[A-Za-z][A-Za-z0-9_]*::)*[A-Za-z][A-Za-z0-9_]*))/;
311 0         0 $saw_moose = 1;
312             }
313             }
314 0         0 $c->{last_found_by_skimming} = $last_found;
315 0         0 pos($$rstr) = $pos;
316             }
317              
318             sub _scan {
319 3226     3226   7116 my ($self, $c, $rstr, $parent_scope) = @_;
320              
321 3226 100       4551 if (@{$c->{stack}} > 90) {
  3226         7070  
322 1         5 _error("deep recursion found");
323 1         2 $c->{ended} = 1;
324             }
325              
326 3226         3771 _dump_stack($c, "BEGIN SCOPE") if DEBUG;
327              
328             # found __DATA|END__ somewhere?
329 3226 100       5689 return $c if $c->{ended};
330              
331 3225         4484 my $wants_doc = $c->{wants_doc};
332 3225         4018 my $line_top = 1;
333 3225         3745 my $waiting_for_a_block;
334              
335 3225         3697 my $current_scope = 0;
336 3225         5551 my ($token, $token_desc, $token_type) = ('', '', '');
337 3225         4791 my ($prev_token, $prev_token_type) = ('', '');
338 3225         13128 my ($stack, $unstack);
339 3225         0 my (@keywords, @tokens, @scope_tokens);
340 3225         0 my $caller_package;
341 3225         0 my $prepend;
342 3225         0 my ($pos, $c1);
343 3225         3849 my $prev_pos = 0;
344 3225         5987 while(defined($pos = pos($$rstr))) {
345 49219         54583 $token = undef;
346              
347             # cache first letter for better performance
348 49219         65340 $c1 = substr($$rstr, $pos, 1);
349              
350 49219 100       68068 if ($line_top) {
351 7996 100       12353 if ($c1 eq '=') {
352 10 50       672 if ($$rstr =~ m/\G($re_pod)/gcsx) {
353 10 50       21 ($token, $token_desc, $token_type) = ($1, 'POD', '') if $wants_doc;
354 10         17 next;
355             }
356             }
357             }
358 49209 100       73012 if ($c1 eq "\n") {
359 4501         8550 pos($$rstr)++;
360 4501         6103 $line_top = 1;
361 4501         5865 next;
362             }
363              
364 44708         47444 $line_top = 0;
365             # ignore whitespaces
366 44708 100       197956 if ($c1 eq ' ') {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
367 15588         26570 pos($$rstr)++;
368 15588         21356 next;
369             } elsif ($c1 eq '_') {
370 57         140 my $c2 = substr($$rstr, $pos + 1, 1);
371 57 100 100     245 if ($c2 eq '_' and $$rstr =~ m/\G(__(?:DATA|END)__\b)(?!\s*=>)/gc) {
372 1 50       2 if ($wants_doc) {
373 0         0 ($token, $token_desc, $token_type) = ($1, 'END_OF_CODE', '');
374 0         0 next;
375             } else {
376 1         3 $c->{ended} = 1;
377 1         3 last;
378             }
379             }
380             } elsif ($c1 eq '#') {
381 260 50       5316 if ($$rstr =~ m{\G($re_comment)}gcs) {
382 260 50       607 ($token, $token_desc, $token_type) = ($1, 'COMMENT', '') if $wants_doc;
383 260         360 $line_top = 1;
384 260         341 next;
385             }
386             } elsif ($c1 eq ';') {
387 2868         5710 pos($$rstr) = $pos + 1;
388 2868         5457 ($token, $token_desc, $token_type) = ($c1, ';', ';');
389 2868         3737 $current_scope |= F_STATEMENT_END|F_EXPR_END;
390 2868         3621 next;
391             } elsif ($c1 eq '$') {
392 3828         5707 my $c2 = substr($$rstr, $pos + 1, 1);
393 3828 100 66     31085 if ($c2 eq '#') {
    100 100        
    100          
    100          
    100          
    100          
394 32 100       508 if (substr($$rstr, $pos + 2, 1) eq '{') {
    100          
    100          
395 2 50       9 if ($$rstr =~ m{\G(\$\#\{[\w\s]+\})}gc) {
396 0         0 ($token, $token_desc, $token_type) = ($1, '$#{NAME}', 'EXPR');
397 0         0 next;
398             } else {
399 2         5 pos($$rstr) = $pos + 3;
400 2         6 ($token, $token_desc, $token_type) = ('$#{', '$#{', 'EXPR');
401 2         4 $stack = [$token, $pos, 'VARIABLE'];
402 2         6 next;
403             }
404             } elsif ($$rstr =~ m{\G(\$\#(?:$re_namespace))}gc) {
405 14         46 ($token, $token_desc, $token_type) = ($1, '$#NAME', 'EXPR');
406 14         25 next;
407             } elsif ($prev_token_type eq 'ARROW') {
408 2         7 my $c3 = substr($$rstr, $pos + 2, 1);
409 2 50       31 if ($c3 eq '*') {
410 2         7 pos($$rstr) = $pos + 3;
411 2         5 ($token, $token_desc, $token_type) = ('$#*', 'VARIABLE', 'VARIABLE');
412 2         8 $c->add_perl('5.020', '->$#*');
413 2         4 next;
414             }
415             } else {
416 14         31 pos($$rstr) = $pos + 2;
417 14         27 ($token, $token_desc, $token_type) = ('$#', 'SPECIAL_VARIABLE', 'EXPR');
418 14         20 next;
419             }
420             } elsif ($c2 eq '$') {
421 44 100       555 if ($$rstr =~ m{\G(\$(?:\$)+(?:$re_namespace))}gc) {
422 42         100 ($token, $token_desc, $token_type) = ($1, '$$NAME', 'VARIABLE');
423 42         55 next;
424             } else {
425 2         9 pos($$rstr) = $pos + 2;
426 2         8 ($token, $token_desc, $token_type) = ('$$', 'SPECIAL_VARIABLE', 'EXPR');
427 2         5 next;
428             }
429             } elsif ($c2 eq '{') {
430 10 100       57 if ($$rstr =~ m{\G(\$\{[\w\s]+\})}gc) {
    50          
431 2         8 ($token, $token_desc, $token_type) = ($1, '${NAME}', 'VARIABLE');
432 2 50 33     9 if ($prev_token_type eq 'KEYWORD' and $c->token_expects_fh_or_block_list($prev_token)) {
433 0         0 $token_type = '';
434 0         0 next;
435             }
436             } elsif ($$rstr =~ m{\G(\$\{\^[A-Z_]+\})}gc) {
437 0         0 ($token, $token_desc, $token_type) = ($1, '${^NAME}', 'VARIABLE');
438 0 0 0     0 if ($token eq '${^CAPTURE}' or $token eq '${^CAPTURE_ALL}') {
439 0         0 $c->add_perl('5.026', '${^CAPTURE}');
440             }
441 0 0       0 if ($token eq '${^SAFE_LOCALES}') {
442 0         0 $c->add_perl('5.028', '${^SAFE_LOCALES}');
443             }
444             } else {
445 8         22 pos($$rstr) = $pos + 2;
446 8         21 ($token, $token_desc, $token_type) = ('${', '${', 'VARIABLE');
447 8         32 $stack = [$token, $pos, 'VARIABLE'];
448             }
449 10 100       25 if ($parent_scope & F_EXPECTS_BRACKET) {
450 3         7 $current_scope |= F_SCOPE_END;
451             }
452 10         15 next;
453             } elsif ($c2 eq '*' and $prev_token_type eq 'ARROW') {
454 2         5 pos($$rstr) = $pos + 2;
455 2         4 ($token, $token_desc, $token_type) = ('$*', '$*', 'VARIABLE');
456 2         9 $c->add_perl('5.020', '->$*');
457 2         3 next;
458             } elsif ($c2 eq '+' or $c2 eq '-') {
459 2         5 pos($$rstr) = $pos + 2;
460 2         7 ($token, $token_desc, $token_type) = ('$'.$c2, 'SPECIAL_VARIABLE', 'VARIABLE');
461 2         8 $c->add_perl('5.010', '$'.$c2);
462 2         4 next;
463             } elsif ($$rstr =~ m{$g_re_scalar_variable}gc) {
464 3736         8622 ($token, $token_desc, $token_type) = ($1, '$NAME', 'VARIABLE');
465 3736         5211 next;
466             } else {
467 2         7 pos($$rstr) = $pos + 1;
468 2         25 ($token, $token_desc, $token_type) = ($c1, $c1, 'VARIABLE');
469 2         5 next;
470             }
471             } elsif ($c1 eq '@') {
472 321         551 my $c2 = substr($$rstr, $pos + 1, 1);
473 321 100 100     2888 if ($c2 eq '_' and $$rstr =~ m{\G\@_\b}gc) {
    100 100        
    100          
    100          
    100          
    100          
    50          
474 122         244 ($token, $token_desc, $token_type) = ('@_', 'SPECIAL_VARIABLE', 'VARIABLE');
475 122         183 next;
476             } elsif ($c2 eq '{') {
477 37 50       212 if ($$rstr =~ m{\G(\@\{[\w\s]+\})}gc) {
    100          
478 0         0 ($token, $token_desc, $token_type) = ($1, '@{NAME}', 'VARIABLE');
479 0 0 0     0 if ($token eq '@{^CAPTURE}' or $token eq '@{^CAPTURE_ALL}') {
480 0         0 $c->add_perl('5.026', '@{^CAPTURE}');
481             }
482             } elsif ($$rstr =~ m{\G(\@\{\^[A-Z_]+\})}gc) {
483 2         7 ($token, $token_desc, $token_type) = ($1, '@{^NAME}', 'VARIABLE');
484 2 50 33     7 if ($token eq '@{^CAPTURE}' or $token eq '@{^CAPTURE_ALL}') {
485 2         5 $c->add_perl('5.026', '@{^CAPTURE}');
486             }
487             } else {
488 35         84 pos($$rstr) = $pos + 2;
489 35         81 ($token, $token_desc, $token_type) = ('@{', '@{', 'VARIABLE');
490 35         113 $stack = [$token, $pos, 'VARIABLE'];
491             }
492 37 100       93 if ($prev_token_type eq 'ARROW') {
493 5         12 $c->add_perl('5.020', '->@{}');
494             }
495 37 50       128 if ($parent_scope & F_EXPECTS_BRACKET) {
496 0         0 $current_scope |= F_SCOPE_END;
497             }
498 37         62 next;
499             } elsif ($c2 eq '$') {
500 37 100       410 if ($$rstr =~ m{\G(\@\$(?:$re_namespace))}gc) {
501 35         78 ($token, $token_desc, $token_type) = ($1, '@$NAME', 'VARIABLE');
502 35         49 next;
503             } else {
504 2         6 pos($$rstr) = $pos + 2;
505 2         4 ($token, $token_desc, $token_type) = ('@$', '@$', 'VARIABLE');
506 2         4 next;
507             }
508             } elsif ($prev_token_type eq 'ARROW') {
509             # postderef
510 11 100       23 if ($c2 eq '*') {
511 5         10 pos($$rstr) = $pos + 2;
512 5         11 ($token, $token_desc, $token_type) = ('@*', '@*', 'VARIABLE');
513 5         16 $c->add_perl('5.020', '->@*');
514 5         8 next;
515             } else {
516 6         12 pos($$rstr) = $pos + 1;
517 6         12 ($token, $token_desc, $token_type) = ('@', '@', 'VARIABLE');
518 6         18 $c->add_perl('5.020', '->@');
519 6         9 next;
520             }
521             } elsif ($c2 eq '[') {
522 1         2 pos($$rstr) = $pos + 2;
523 1         3 ($token, $token_desc, $token_type) = ('@[', 'SPECIAL_VARIABLE', 'VARIABLE');
524 1         2 next;
525             } elsif ($c2 eq '+' or $c2 eq '-') {
526 2         7 pos($$rstr) = $pos + 2;
527 2         7 ($token, $token_desc, $token_type) = ('@'.$c2, 'SPECIAL_VARIABLE', 'VARIABLE');
528 2         8 $c->add_perl('5.010', '@'.$c2);
529 2         4 next;
530             } elsif ($$rstr =~ m{\G(\@(?:$re_namespace))}gc) {
531 111         285 ($token, $token_desc, $token_type) = ($1, '@NAME', 'VARIABLE');
532 111         162 next;
533             } else {
534 0         0 pos($$rstr) = $pos + 1;
535 0         0 ($token, $token_desc, $token_type) = ($c1, $c1, 'VARIABLE');
536 0         0 next;
537             }
538             } elsif ($c1 eq '%') {
539 117         224 my $c2 = substr($$rstr, $pos + 1, 1);
540 117 100 66     2009 if ($c2 eq '{') {
    100 66        
    100          
    100          
    100          
    100          
    50          
541 42 50       208 if ($$rstr =~ m{\G(\%\{[\w\s]+\})}gc) {
    100          
542 0         0 ($token, $token_desc, $token_type) = ($1, '%{NAME}', 'VARIABLE');
543             } elsif ($$rstr =~ m{\G(\%\{\^[A-Z_]+\})}gc) {
544 2         7 ($token, $token_desc, $token_type) = ($1, '%{^NAME}', 'VARIABLE');
545 2 50 66     9 if ($token eq '%{^CAPTURE}' or $token eq '%{^CAPTURE_ALL}') {
546 2         6 $c->add_perl('5.026', '%{^CAPTURE}');
547             }
548             } else {
549 40         93 pos($$rstr) = $pos + 2;
550 40         82 ($token, $token_desc, $token_type) = ('%{', '%{', 'VARIABLE');
551 40         102 $stack = [$token, $pos, 'VARIABLE'];
552             }
553 42 100       103 if ($prev_token_type eq 'ARROW') {
554 4         11 $c->add_perl('5.020', '->%{');
555             }
556 42 50       93 if ($parent_scope & F_EXPECTS_BRACKET) {
557 0         0 $current_scope |= F_SCOPE_END;
558             }
559 42         58 next;
560             } elsif ($c2 eq '=') {
561 1         3 pos($$rstr) = $pos + 2;
562 1         4 ($token, $token_desc, $token_type) = ('%=', '%=', 'OP');
563 1         2 next;
564             } elsif ($$rstr =~ m{\G(\%\$(?:$re_namespace))}gc) {
565 5         15 ($token, $token_desc, $token_type) = ($1, '%$NAME', 'VARIABLE');
566 5         28 next;
567             } elsif ($$rstr =~ m{\G(\%(?:$re_namespace))}gc) {
568 57         168 ($token, $token_desc, $token_type) = ($1, '%NAME', 'VARIABLE');
569 57         86 next;
570             } elsif ($prev_token_type eq 'VARIABLE' or $prev_token_type eq 'EXPR') {
571 4         11 pos($$rstr) = $pos + 1;
572 4         10 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
573 4         6 next;
574             } elsif ($prev_token_type eq 'ARROW') {
575 6 100       12 if ($c2 eq '*') {
576 2         6 pos($$rstr) = $pos + 2;
577 2         7 ($token, $token_desc, $token_type) = ('%*', '%*', 'VARIABLE');
578 2         7 $c->add_perl('5.020', '->%*');
579 2         4 next;
580             } else {
581 4         8 pos($$rstr) = $pos + 1;
582 4         9 ($token, $token_desc, $token_type) = ('%', '%', 'VARIABLE');
583 4         11 $c->add_perl('5.020', '->%');
584 4         7 next;
585             }
586             } elsif ($c2 eq '+' or $c2 eq '-') {
587 2         8 pos($$rstr) = $pos + 2;
588 2         8 ($token, $token_desc, $token_type) = ('%'.$c2, 'SPECIAL_VARIABLE', 'VARIABLE');
589 2         9 $c->add_perl('5.010', '%'.$c2);
590 2         5 next;
591             } else {
592 0         0 pos($$rstr) = $pos + 1;
593 0         0 ($token, $token_desc, $token_type) = ($c1, $c1, 'VARIABLE');
594 0         0 next;
595             }
596             } elsif ($c1 eq '*') {
597 89         165 my $c2 = substr($$rstr, $pos + 1, 1);
598 89 100       761 if ($c2 eq '{') {
    100          
    100          
    100          
599 15 100       58 if ($prev_token_type eq 'ARROW') {
    50          
600 2         5 pos($$rstr) = $pos + 2;
601 2         5 ($token, $token_desc, $token_type) = ('*{', '*{', 'VARIABLE');
602 2         8 $c->add_perl('5.020', '->*{}');
603 2         3 next;
604             } elsif ($$rstr =~ m{\G(\*\{[\w\s]+\})}gc) {
605 0         0 ($token, $token_desc, $token_type) = ($1, '*{NAME}', 'VARIABLE');
606 0 0 0     0 if ($prev_token eq 'KEYWORD' and $c->token_expects_fh_or_block_list($prev_token)) {
607 0         0 $token_type = '';
608 0         0 next;
609             }
610             } else {
611 13         28 pos($$rstr) = $pos + 2;
612 13         24 ($token, $token_desc, $token_type) = ('*{', '*{', 'VARIABLE');
613 13         35 $stack = [$token, $pos, 'VARIABLE'];
614             }
615 13 50       26 if ($parent_scope & F_EXPECTS_BRACKET) {
616 0         0 $current_scope |= F_SCOPE_END;
617             }
618 13         18 next;
619             } elsif ($c2 eq '*') {
620 3 50       17 if (substr($$rstr, $pos + 2, 1) eq '=') {
    100          
621 0         0 pos($$rstr) = $pos + 3;
622 0         0 ($token, $token_desc, $token_type) = ('**=', '**=', 'OP');
623 0         0 next;
624             } elsif ($prev_token_type eq 'ARROW') {
625 2         5 pos($$rstr) = $pos + 2;
626 2         4 ($token, $token_desc, $token_type) = ('**', '**', 'VARIABLE');
627 2         10 $c->add_perl('5.020', '->**');
628 2         3 next;
629             } else {
630 1         4 pos($$rstr) = $pos + 2;
631 1         3 ($token, $token_desc, $token_type) = ('**', '**', 'OP');
632 1         2 next;
633             }
634             } elsif ($c2 eq '=') {
635 2         7 pos($$rstr) = $pos + 2;
636 2         6 ($token, $token_desc, $token_type) = ('*=', '*=', 'OP');
637 2         3 next;
638             } elsif ($$rstr =~ m{\G(\*(?:$re_namespace))}gc) {
639 29         85 ($token, $token_desc, $token_type) = ($1, '*NAME', 'VARIABLE');
640 29         39 next;
641             } else {
642 40         80 pos($$rstr) = $pos + 1;
643 40         72 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
644 40         51 next;
645             }
646             } elsif ($c1 eq '&') {
647 129         243 my $c2 = substr($$rstr, $pos + 1, 1);
648 129 100       1299 if ($c2 eq '&') {
    50          
    100          
    100          
    100          
    100          
    100          
649 58         132 pos($$rstr) = $pos + 2;
650 58         153 ($token, $token_desc, $token_type) = ('&&', '&&', 'OP');
651 58         83 next;
652             } elsif ($c2 eq '=') {
653 0         0 pos($$rstr) = $pos + 2;
654 0         0 ($token, $token_desc, $token_type) = ('&=', '&=', 'OP');
655 0         0 next;
656             } elsif ($c2 eq '{') {
657 8 50       57 if ($$rstr =~ m{\G(\&\{[\w\s]+\})}gc) {
658 0         0 ($token, $token_desc, $token_type) = ($1, '&{NAME}', 'EXPR');
659             } else {
660 8         19 pos($$rstr) = $pos + 2;
661 8         16 ($token, $token_desc, $token_type) = ('&{', '&{', 'EXPR');
662 8         17 $stack = [$token, $pos, 'FUNC'];
663             }
664 8 50       27 if ($parent_scope & F_EXPECTS_BRACKET) {
665 0         0 $current_scope |= F_SCOPE_END;
666             }
667 8         13 next;
668             } elsif ($c2 eq '.') {
669 2 100       6 if (substr($$rstr, $pos + 2, 1) eq '=') {
670 1         4 pos($$rstr) = $pos + 3;
671 1         3 ($token, $token_desc, $token_type) = ('&.=', '&.=', 'OP');
672             } else {
673 1         3 pos($$rstr) = $pos + 2;
674 1         3 ($token, $token_desc, $token_type) = ('&.', '&.', 'OP');
675             }
676 2         5 $c->add_perl('5.022', '&.');
677 2         4 next;
678             } elsif ($$rstr =~ m{\G(\&(?:$re_namespace))}gc) {
679 48         113 ($token, $token_desc, $token_type) = ($1, '&NAME', 'EXPR');
680 48         75 next;
681             } elsif ($$rstr =~ m{\G(\&\$(?:$re_namespace))}gc) {
682 3         8 ($token, $token_desc, $token_type) = ($1, '&$NAME', 'EXPR');
683 3         4 next;
684             } elsif ($prev_token_type eq 'ARROW') {
685 2 50       8 if ($c2 eq '*') {
686 2         6 pos($$rstr) = $pos + 2;
687 2         10 ($token, $token_desc, $token_type) = ('&*', '&*', 'VARIABLE');
688 2         8 $c->add_perl('5.020', '->&*');
689 2         4 next;
690             }
691             } else {
692 8         23 pos($$rstr) = $pos + 1;
693 8         15 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
694 8         14 next;
695             }
696             } elsif ($c1 eq '\\') {
697 70         153 my $c2 = substr($$rstr, $pos + 1, 1);
698 70 50       146 if ($c2 eq '{') {
699 0 0       0 if ($$rstr =~ m{\G(\\\{[\w\s]+\})}gc) {
700 0         0 ($token, $token_desc, $token_type) = ($1, '\\{NAME}', 'VARIABLE');
701             } else {
702 0         0 pos($$rstr) = $pos + 2;
703 0         0 ($token, $token_desc, $token_type) = ('\\{', '\\{', 'VARIABLE');
704 0         0 $stack = [$token, $pos, 'VARIABLE'];
705             }
706 0 0       0 if ($parent_scope & F_EXPECTS_BRACKET) {
707 0         0 $current_scope |= F_SCOPE_END;
708             }
709 0         0 next;
710             } else {
711 70         142 pos($$rstr) = $pos + 1;
712 70         149 ($token, $token_desc, $token_type) = ($c1, $c1, '');
713 70         123 next;
714             }
715             } elsif ($c1 eq '-') {
716 1267         2055 my $c2 = substr($$rstr, $pos + 1, 1);
717 1267 100       2315 if ($c2 eq '>') {
    100          
    100          
    100          
718 1103         2017 pos($$rstr) = $pos + 2;
719 1103         1913 ($token, $token_desc, $token_type) = ('->', 'ARROW', 'ARROW');
720 1103 100 100     2803 if ($prev_token_type eq 'WORD' or $prev_token_type eq 'KEYWORD') {
721 51         75 $caller_package = $prev_token;
722 51         101 $current_scope |= F_KEEP_TOKENS;
723             }
724 1103         1447 next;
725             } elsif ($c2 eq '-') {
726 4         13 pos($$rstr) = $pos + 2;
727 4         11 ($token, $token_desc, $token_type) = ('--', '--', $prev_token_type);
728 4         8 next;
729             } elsif ($c2 eq '=') {
730 5         13 pos($$rstr) = $pos + 2;
731 5         9 ($token, $token_desc, $token_type) = ('-=', '-=', 'OP');
732 5         9 next;
733             } elsif ($$rstr =~ m{\G(\-[ABCMORSTWXbcdefgkloprstuwxz]\b)}gc) {
734 4         13 ($token, $token_desc, $token_type) = ($1, 'FILE_TEST', 'EXPR');
735 4         8 next;
736             } else {
737 151         290 pos($$rstr) = $pos + 1;
738 151         279 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
739 151         235 next;
740             }
741             } elsif ($c1 eq q{"}) {
742 439 100       4770 if ($$rstr =~ m{\G(?:\"($re_str_in_double_quotes)\")}gcs) {
743 438         1509 ($token, $token_desc, $token_type) = ([$1, q{"}], 'STRING', 'STRING');
744 438         653 next;
745             }
746             } elsif ($c1 eq q{'}) {
747 903 50       9024 if ($$rstr =~ m{\G(?:\'($re_str_in_single_quotes)\')}gcs) {
748 903         2954 ($token, $token_desc, $token_type) = ([$1, q{'}], 'STRING', 'STRING');
749 903         1324 next;
750             }
751             } elsif ($c1 eq '`') {
752 0 0       0 if ($$rstr =~ m{\G(?:\`($re_str_in_backticks)\`)}gcs) {
753 0         0 ($token, $token_desc, $token_type) = ([$1, q{`}], 'BACKTICK', 'EXPR');
754 0         0 next;
755             }
756             } elsif ($c1 eq '/') {
757 144 100 100     708 if ($prev_token_type eq '' or $prev_token_type eq 'OP' or ($prev_token_type eq 'KEYWORD' and $regexp_may_follow{$prev_token})) { # undoubtedly regexp
      100        
      100        
758 97 100       277 if (my $regexp = $self->_match_regexp0($c, $rstr, $pos, 'm')) {
759 96         211 ($token, $token_desc, $token_type) = ($regexp, 'REGEXP', 'EXPR');
760 96         164 next;
761             } else {
762             # the above may fail
763 1         2 _debug("REGEXP ERROR: $@") if DEBUG;
764 1         2 pos($$rstr) = $pos;
765             }
766             }
767 48 50 33     329 if (($prev_token_type eq '' or (!($current_scope & F_EXPR) and $prev_token_type eq 'WORD')) or ($prev_token_type eq 'KEYWORD' and @keywords and $prev_token eq $keywords[-1] and $regexp_may_follow{$prev_token})) {
      66        
      66        
      66        
      33        
      33        
768              
769 1 50       3 if (my $regexp = $self->_match_regexp0($c, $rstr, $pos)) {
770 0         0 ($token, $token_desc, $token_type) = ($regexp, 'REGEXP', 'EXPR');
771 0         0 next;
772             } else {
773             # the above may fail
774 1         2 _debug("REGEXP ERROR: $@") if DEBUG;
775 1         2 pos($$rstr) = $pos;
776             }
777             }
778 48         104 my $c2 = substr($$rstr, $pos + 1, 1);
779 48 100       93 if ($c2 eq '/') {
780 9 100       23 if (substr($$rstr, $pos + 2, 1) eq '=') {
781 2         5 pos($$rstr) = $pos + 3;
782 2         6 ($token, $token_desc, $token_type) = ('//=', '//=', 'OP');
783 2         10 $c->add_perl('5.010', '//=');
784 2         3 next;
785             } else {
786 7         13 pos($$rstr) = $pos + 2;
787 7         14 ($token, $token_desc, $token_type) = ('//', '//', 'OP');
788 7         21 $c->add_perl('5.010', '//');
789 7         11 next;
790             }
791             }
792 39 100       78 if ($c2 eq '=') { # this may be a part of /=.../
793 1         3 pos($$rstr) = $pos + 2;
794 1         3 ($token, $token_desc, $token_type) = ('/=', '/=', 'OP');
795 1         1 next;
796             } else {
797 38         95 pos($$rstr) = $pos + 1;
798 38         78 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
799 38         53 next;
800             }
801             } elsif ($c1 eq '{') {
802 1842 100       13442 if ($$rstr =~ m{$g_re_hash_shortcut}gc) {
803 884         1834 ($token, $token_desc) = ($1, '{EXPR}');
804 884 100       1549 if ($current_scope & F_EVAL) {
805 1         2 $current_scope &= MASK_EVAL;
806 1 50       4 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
807             }
808 884 100       1472 if ($parent_scope & F_EXPECTS_BRACKET) {
809 8         13 $current_scope |= F_SCOPE_END;
810 8         13 next;
811             }
812 876 100 100     2244 if ($prev_token_type eq 'ARROW' or $prev_token_type eq 'VARIABLE') {
    100 100        
    100          
813 755         946 $token_type = 'VARIABLE';
814 755         928 next;
815             } elsif ($waiting_for_a_block) {
816 87         123 $waiting_for_a_block = 0;
817 87 100 100     273 if (@keywords and $c->token_expects_block($keywords[0])) {
818 75         116 my $first_token = $keywords[0];
819 75         105 $current_scope |= F_EXPR_END;
820 75 100 100     204 if ($c->token_defines_sub($first_token) and $c->has_callback_for(sub => $first_token)) {
821 3         15 $c->run_callback_for(sub => $first_token, \@tokens);
822 3         6 $current_scope &= MASK_KEEP_TOKENS;
823 3         7 @tokens = ();
824             }
825             }
826 87         143 next;
827             } elsif ($prev_token_type eq 'KEYWORD' and $c->token_expects_fh_or_block_list($prev_token)) {
828 15         20 $token_type = '';
829 15         21 next;
830             } else {
831 19         29 $token_type = 'EXPR';
832 19         25 next;
833             }
834             }
835 958         2104 pos($$rstr) = $pos + 1;
836 958         1769 ($token, $token_desc) = ($c1, $c1);
837 958         1250 my $stack_owner;
838 958 100       1656 if (@keywords) {
839 765         1680 for(my $i = @keywords; $i > 0; $i--) {
840 801         1382 my $keyword = $keywords[$i - 1];
841 801 100       1576 if ($c->token_expects_block($keyword)) {
842 724         945 $stack_owner = $keyword;
843 724 100 100     1578 if (@tokens and $c->token_defines_sub($keyword) and $c->has_callback_for(sub => $keyword)) {
      100        
844 66         191 $c->run_callback_for(sub => $keyword, \@tokens);
845 66         1247 $current_scope &= MASK_KEEP_TOKENS;
846 66         180 @tokens = ();
847             }
848 724         1177 last;
849             }
850             }
851             }
852 958   100     2975 $stack = [$token, $pos, $stack_owner || ''];
853 958 100       1845 if ($parent_scope & F_EXPECTS_BRACKET) {
854 62         74 $current_scope |= F_SCOPE_END|F_STATEMENT_END|F_EXPR_END;
855 62         77 next;
856             }
857 896 100 100     2891 if ($prev_token_type eq 'ARROW' or $prev_token_type eq 'VARIABLE') {
    100          
858 35         53 $token_type = 'VARIABLE';
859             } elsif ($waiting_for_a_block) {
860 728         951 $waiting_for_a_block = 0;
861             } else {
862 133 100       343 $token_type = (($current_scope | $parent_scope) & F_KEEP_TOKENS) ? 'EXPR' : '';
863             }
864 896         1221 next;
865             } elsif ($c1 eq '[') {
866 395 100       3213 if ($$rstr =~ m{\G(\[(?:$re_nonblock_chars)\])}gc) {
867 208         477 ($token, $token_desc, $token_type) = ($1, '[EXPR]', 'VARIABLE');
868 208         305 next;
869             } else {
870 187         394 pos($$rstr) = $pos + 1;
871 187         339 ($token, $token_desc, $token_type) = ($c1, $c1, 'VARIABLE');
872 187         393 $stack = [$token, $pos, 'VARIABLE'];
873 187         268 next;
874             }
875             } elsif ($c1 eq '(') {
876 1520         3413 my $prototype_re = $c->prototype_re;
877 1520 100 100     12188 if ($waiting_for_a_block and @keywords and $c->token_defines_sub($keywords[-1]) and $$rstr =~ m{$prototype_re}gc) {
    100 100        
      100        
878 127         289 my $proto = $1;
879 127 100       389 if ($proto =~ /^\([\\\$\@\%\&\[\]\*;\+]*\)$/) {
880 56         100 ($token, $token_desc, $token_type) = ($proto, '(PROTOTYPE)', '');
881             } else {
882 71         141 ($token, $token_desc, $token_type) = ($proto, '(SIGNATURES)', '');
883 71         179 $c->add_perl('5.020', 'signatures');
884             }
885 127         202 next;
886             } elsif ($$rstr =~ m{\G\(((?:$re_nonblock_chars)(?
887 302         1557 ($token, $token_desc, $token_type) = ([[[$1, 'EXPR']]], '()', 'EXPR');
888 302 100 100     1159 if ($prev_token_type eq 'KEYWORD' and @keywords and $keywords[-1] eq $prev_token and !$c->token_expects_expr_block($prev_token)) {
      66        
      100        
889 54 100       120 if ($prev_token eq 'eval') {
890 1         1 $current_scope &= MASK_EVAL;
891 1 50       4 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
892             }
893 54         89 pop @keywords;
894             }
895 302         495 next;
896             } else {
897 1091         2342 pos($$rstr) = $pos + 1;
898 1091         1996 ($token, $token_desc, $token_type) = ($c1, $c1, 'EXPR');
899 1091         1267 my $stack_owner;
900 1091 100       1844 if (@keywords) {
901 612         1290 for (my $i = @keywords; $i > 0; $i--) {
902 664         1108 my $keyword = $keywords[$i - 1];
903 664 100       1263 if ($c->token_expects_block($keyword)) {
904 215         287 $stack_owner = $keyword;
905 215         363 last;
906             }
907             }
908             }
909 1091   100     3627 $stack = [$token, $pos, $stack_owner || ''];
910 1091         1854 next;
911             }
912             } elsif ($c1 eq '}') {
913 1061         1992 pos($$rstr) = $pos + 1;
914 1061         1851 ($token, $token_desc, $token_type) = ($c1, $c1, '');
915 1061         1366 $unstack = $token;
916 1061         1416 $current_scope |= F_STATEMENT_END|F_EXPR_END;
917 1061         1349 next;
918             } elsif ($c1 eq ']') {
919 96         213 pos($$rstr) = $pos + 1;
920 96         196 ($token, $token_desc, $token_type) = ($c1, $c1, '');
921 96         157 $unstack = $token;
922 96         143 next;
923             } elsif ($c1 eq ')') {
924 1091         2074 pos($$rstr) = $pos + 1;
925 1091         2008 ($token, $token_desc, $token_type) = ($c1, $c1, '');
926 1091         1377 $unstack = $token;
927 1091         1402 next;
928             } elsif ($c1 eq '<') {
929 93         220 my $c2 = substr($$rstr, $pos + 1, 1);
930 93 100       590 if ($c2 eq '<'){
    100          
    100          
    100          
931 19 100       171 if ($$rstr =~ m{\G(<<(?:
    100          
932             \\. |
933             \w+ |
934             [./-] |
935             \[[^\]]*\] |
936             \{[^\}]*\} |
937             \* |
938             \? |
939             \~ |
940             \$ |
941             )*(?>)}gcx) {
942 1         4 ($token, $token_desc, $token_type) = ($1, '<>', 'EXPR');
943 1         4 $c->add_perl('5.022', '<>');
944 1         2 next;
945             } elsif ($$rstr =~ m{\G<<~?\s*(?:
946             \\?[A-Za-z_][\w]* |
947             "(?:[^\\"]*(?:\\.[^\\"]*)*)" |
948             '(?:[^\\']*(?:\\.[^\\']*)*)' |
949             `(?:[^\\`]*(?:\\.[^\\`]*)*)`
950             )}sx) {
951 16 100       85 if (my $heredoc = $self->_match_heredoc($c, $rstr)) {
952 14         34 ($token, $token_desc, $token_type) = ($heredoc, 'HEREDOC', 'EXPR');
953 14         26 next;
954             } else {
955             # the above may fail
956 2         5 pos($$rstr) = $pos;
957             }
958             }
959 4 50       12 if (substr($$rstr, $pos + 2, 1) eq '=') {
960 0         0 pos($$rstr) = $pos + 3;
961 0         0 ($token, $token_desc, $token_type) = ('<<=', '<<=', 'OP');
962 0         0 next;
963             } else {
964 4         7 pos($$rstr) = $pos + 2;
965 4         8 ($token, $token_desc, $token_type) = ('<<', '<<', 'OP');
966 4         6 next;
967             }
968             } elsif ($c2 eq '=') {
969 10 100       34 if (substr($$rstr, $pos + 2, 1) eq '>') {
970 1         3 pos($$rstr) = $pos + 3;
971 1         3 ($token, $token_desc, $token_type) = ('<=>', '<=>', 'OP');
972 1         2 next;
973             } else {
974 9         22 pos($$rstr) = $pos + 2;
975 9         35 ($token, $token_desc, $token_type) = ('<=', '<=', 'OP');
976 9         16 next;
977             }
978             } elsif ($c2 eq '>') {
979 1         2 pos($$rstr) = $pos + 2;
980 1         3 ($token, $token_desc, $token_type) = ('<>', '<>', 'OP');
981 1         2 next;
982             } elsif ($$rstr =~ m{\G(<(?:
983             \\. |
984             \w+ |
985             [./-] |
986             \[[^\]]*\] |
987             \{[^\}]*\} |
988             \* |
989             \? |
990             \~ |
991             \$ |
992             )*(?)}gcx) {
993 12         35 ($token, $token_desc, $token_type) = ($1, '', 'EXPR');
994 12         17 next;
995             } else {
996 51         109 pos($$rstr) = $pos + 1;
997 51         111 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
998 51         69 next;
999             }
1000             } elsif ($c1 eq ':') {
1001 325         611 my $c2 = substr($$rstr, $pos + 1, 1);
1002 325 100       662 if ($c2 eq ':') {
1003 21         69 pos($$rstr) = $pos + 2;
1004 21         51 ($token, $token_desc, $token_type) = ('::', '::', '');
1005 21         33 next;
1006             }
1007 304 100 100     1023 if ($waiting_for_a_block and @keywords and $c->token_defines_sub($keywords[-1])) {
      100        
1008 88         336 while($$rstr =~ m{\G\s*(:?\s*[\w]+)}gcs) {
1009 145         200 my $startpos = pos($$rstr);
1010 145 100       338 if (substr($$rstr, $startpos, 1) eq '(') {
1011 114         200 my @nest = '(';
1012 114         204 pos($$rstr) = $startpos + 1;
1013 114         179 my ($p, $c1);
1014 114         202 while(defined($p = pos($$rstr))) {
1015 243         305 $c1 = substr($$rstr, $p, 1);
1016 243 50       357 if ($c1 eq '\\') {
1017 0         0 pos($$rstr) = $p + 2;
1018 0         0 next;
1019             }
1020 243 100       313 if ($c1 eq ')') {
1021 120         161 pop @nest;
1022 120         199 pos($$rstr) = $p + 1;
1023 120 100       467 last unless @nest;
1024             }
1025 129 100       223 if ($c1 eq '(') {
1026 6         9 push @nest, $c1;
1027 6         8 pos($$rstr) = $p + 1;
1028 6         11 next;
1029             }
1030 123 100       325 $$rstr =~ m{\G([^\\()]+)}gc and next;
1031             }
1032             }
1033             }
1034 88         211 $token = substr($$rstr, $pos, pos($$rstr) - $pos);
1035 88         158 ($token_desc, $token_type) = ('ATTRIBUTE', '');
1036 88 100       199 if ($token =~ /^:prototype\(/) {
1037 2         7 $c->add_perl('5.020', ':prototype');
1038             }
1039 88         137 next;
1040             } else {
1041 216         432 pos($$rstr) = $pos + 1;
1042 216         442 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1043 216         336 next;
1044             }
1045             } elsif ($c1 eq '=') {
1046 1758         3081 my $c2 = substr($$rstr, $pos + 1, 1);
1047 1758 100       3533 if ($c2 eq '>') {
    100          
    100          
1048 600         1088 pos($$rstr) = $pos + 2;
1049 600         1098 ($token, $token_desc, $token_type) = ('=>', 'COMMA', 'OP');
1050 600 100 100     1512 if (@keywords and $prev_token_type eq 'KEYWORD' and $keywords[-1] eq $prev_token) {
      66        
1051 26         41 pop @keywords;
1052 26 100 100     109 if (!@keywords and ($current_scope & F_KEEP_TOKENS)) {
1053 1         2 $current_scope &= MASK_KEEP_TOKENS;
1054 1         3 @tokens = ();
1055             }
1056             }
1057 600         844 next;
1058             } elsif ($c2 eq '=') {
1059 74         137 pos($$rstr) = $pos + 2;
1060 74         139 ($token, $token_desc, $token_type) = ('==', '==', 'OP');
1061 74         105 next;
1062             } elsif ($c2 eq '~') {
1063 101         226 pos($$rstr) = $pos + 2;
1064 101         211 ($token, $token_desc, $token_type) = ('=~', '=~', 'OP');
1065 101         166 next;
1066             } else {
1067 983         1636 pos($$rstr) = $pos + 1;
1068 983         1711 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1069 983         1280 next;
1070             }
1071             } elsif ($c1 eq '>') {
1072 54         114 my $c2 = substr($$rstr, $pos + 1, 1);
1073 54 50       154 if ($c2 eq '>') {
    100          
1074 0 0       0 if (substr($$rstr, $pos + 2, 1) eq '=') {
1075 0         0 pos($$rstr) = $pos + 3;
1076 0         0 ($token, $token_desc, $token_type) = ('>>=', '>>=', 'OP');
1077 0         0 next;
1078             } else {
1079 0         0 pos($$rstr) = $pos + 2;
1080 0         0 ($token, $token_desc, $token_type) = ('>>', '>>', 'OP');
1081 0         0 next;
1082             }
1083             } elsif ($c2 eq '=') {
1084 4         14 pos($$rstr) = $pos + 2;
1085 4         16 ($token, $token_desc, $token_type) = ('>=', '>=', 'OP');
1086 4         6 next;
1087             } else {
1088 50         93 pos($$rstr) = $pos + 1;
1089 50         91 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1090 50         63 next;
1091             }
1092             } elsif ($c1 eq '+') {
1093 186         380 my $c2 = substr($$rstr, $pos + 1, 1);
1094 186 100       415 if ($c2 eq '+') {
    100          
1095 19 50       61 if (substr($$rstr, $pos + 2, 1) eq '=') {
1096 0         0 pos($$rstr) = $pos + 3;
1097 0         0 ($token, $token_desc, $token_type) = ('++=', '++=', 'OP');
1098 0         0 next;
1099             } else {
1100 19         46 pos($$rstr) = $pos + 2;
1101 19         48 ($token, $token_desc, $token_type) = ('++', '++', $prev_token_type);
1102 19         28 next;
1103             }
1104             } elsif ($c2 eq '=') {
1105 92         148 pos($$rstr) = $pos + 2;
1106 92         187 ($token, $token_desc, $token_type) = ('+=', '+=', 'OP');
1107 92         127 next;
1108             } else {
1109 75         151 pos($$rstr) = $pos + 1;
1110 75         131 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1111 75         119 next;
1112             }
1113             } elsif ($c1 eq '|') {
1114 93         195 my $c2 = substr($$rstr, $pos + 1, 1);
1115 93 100       239 if ($c2 eq '|') {
    100          
    100          
1116 85 100       216 if (substr($$rstr, $pos + 2, 1) eq '=') {
1117 17         38 pos($$rstr) = $pos + 3;
1118 17         52 ($token, $token_desc, $token_type) = ('||=', '||=', 'OP');
1119 17         26 next;
1120             } else {
1121 68         130 pos($$rstr) = $pos + 2;
1122 68         142 ($token, $token_desc, $token_type) = ('||', '||', 'OP');
1123 68         103 next;
1124             }
1125             } elsif ($c2 eq '=') {
1126 1         2 pos($$rstr) = $pos + 2;
1127 1         3 ($token, $token_desc, $token_type) = ('|=', '|=', 'OP');
1128 1         1 next;
1129             } elsif ($c2 eq '.') {
1130 2 100       8 if (substr($$rstr, $pos + 2, 1) eq '=') {
1131 1         3 pos($$rstr) = $pos + 3;
1132 1         3 ($token, $token_desc, $token_type) = ('|.=', '|.=', 'OP');
1133             } else {
1134 1         2 pos($$rstr) = $pos + 2;
1135 1         3 ($token, $token_desc, $token_type) = ('|.', '|.', 'OP');
1136             }
1137 2         7 $c->add_perl('5.022', '|.');
1138 2         3 next;
1139             } else {
1140 5         11 pos($$rstr) = $pos + 1;
1141 5         24 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1142 5         11 next;
1143             }
1144             } elsif ($c1 eq '^') {
1145 4         16 my $c2 = substr($$rstr, $pos + 1, 1);
1146 4 50       20 if ($c2 eq '=') {
    100          
1147 0         0 pos($$rstr) = $pos + 2;
1148 0         0 ($token, $token_desc, $token_type) = ('^=', '^=', 'OP');
1149 0         0 next;
1150             } elsif ($c2 eq '.') {
1151 2 100       8 if (substr($$rstr, $pos + 2, 1) eq '=') {
1152 1         2 pos($$rstr) = $pos + 3;
1153 1         3 ($token, $token_desc, $token_type) = ('^.=', '^.=', 'OP');
1154             } else {
1155 1         3 pos($$rstr) = $pos + 2;
1156 1         3 ($token, $token_desc, $token_type) = ('^.', '^.', 'OP');
1157             }
1158 2         7 $c->add_perl('5.022', '^.');
1159 2         4 next;
1160             } else {
1161 2         8 pos($$rstr) = $pos + 1;
1162 2         7 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1163 2         6 next;
1164             }
1165             } elsif ($c1 eq '!') {
1166 51         141 my $c2 = substr($$rstr, $pos + 1, 1);
1167 51 100       102 if ($c2 eq '~') {
1168 5         39 pos($$rstr) = $pos + 2;
1169 5         24 ($token, $token_desc, $token_type) = ('!~', '!~', 'OP');
1170 5         9 next;
1171             } else {
1172 46         103 pos($$rstr) = $pos + 1;
1173 46         103 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1174 46         66 next;
1175             }
1176             } elsif ($c1 eq '~') {
1177 2         5 my $c2 = substr($$rstr, $pos + 1, 1);
1178 2 100       9 if ($c2 eq '~') {
    50          
1179 1         2 pos($$rstr) = $pos + 2;
1180 1         3 ($token, $token_desc, $token_type) = ('~~', '~~', 'OP');
1181 1         5 $c->add_perl('5.010', '~~');
1182 1         1 next;
1183             } elsif ($c2 eq '.') {
1184 1         3 pos($$rstr) = $pos + 2;
1185 1         2 ($token, $token_desc, $token_type) = ('~.', '~.', 'OP');
1186 1         3 $c->add_perl('5.022', '~.');
1187 1         3 next;
1188             } else {
1189 0         0 pos($$rstr) = $pos + 1;
1190 0         0 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1191 0         0 next;
1192             }
1193             } elsif ($c1 eq ',') {
1194 1390         2694 pos($$rstr) = $pos + 1;
1195 1390         2505 ($token, $token_desc, $token_type) = ($c1, 'COMMA', 'OP');
1196 1390         1724 next;
1197             } elsif ($c1 eq '?') {
1198 131         267 pos($$rstr) = $pos + 1;
1199 131         259 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1200 131         173 next;
1201             } elsif ($c1 eq '.') {
1202 190         373 my $c2 = substr($$rstr, $pos + 1, 1);
1203 190 100       420 if ($c2 eq '.') {
    100          
1204 15 100       43 if (substr($$rstr, $pos + 2, 1) eq '.') {
1205 10         19 pos($$rstr) = $pos + 3;
1206 10         23 ($token, $token_desc, $token_type) = ('...', '...', 'OP');
1207 10         34 $c->add_perl('5.012', '...');
1208 10         14 next;
1209             } else {
1210 5         14 pos($$rstr) = $pos + 2;
1211 5         15 ($token, $token_desc, $token_type) = ('..', '..', 'OP');
1212 5         8 next;
1213             }
1214             } elsif ($c2 eq '=') {
1215 26         61 pos($$rstr) = $pos + 2;
1216 26         62 ($token, $token_desc, $token_type) = ('.=', '.=', 'OP');
1217 26         38 next;
1218             } else {
1219 149         269 pos($$rstr) = $pos + 1;
1220 149         275 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1221 149         200 next;
1222             }
1223             } elsif ($c1 eq '0') {
1224 271         524 my $c2 = substr($$rstr, $pos + 1, 1);
1225 271 100       690 if ($c2 eq 'x') {
    50          
1226 4 50       19 if ($$rstr =~ m{\G(0x[0-9A-Fa-f_]+)}gc) {
1227 4         12 ($token, $token_desc, $token_type) = ($1, 'HEX NUMBER', 'EXPR');
1228 4         7 next;
1229             }
1230             } elsif ($c2 eq 'b') {
1231 0 0       0 if ($$rstr =~ m{\G(0b[01_]+)}gc) {
1232 0         0 ($token, $token_desc, $token_type) = ($1, 'BINARY NUMBER', 'EXPR');
1233 0         0 next;
1234             }
1235             }
1236             }
1237              
1238 8399 100       24134 if ($$rstr =~ m{\G((?:0|[1-9][0-9_]*)(?:\.[0-9][0-9_]*)?)}gc) {
1239 738         1332 my $number = $1;
1240 738         1049 my $p = pos($$rstr);
1241 738         1154 my $n1 = substr($$rstr, $p, 1);
1242 738 100 33     2482 if ($n1 eq '.') {
    50          
1243 9 50       47 if ($$rstr =~ m{\G((?:\.[0-9_])+)}gc) {
    100          
1244 0         0 $number .= $1;
1245 0         0 ($token, $token_desc, $token_type) = ($number, 'VERSION_STRING', 'EXPR');
1246 0         0 next;
1247             } elsif (substr($$rstr, $p, 2) ne '..') {
1248 7         10 $number .= '.';
1249 7         14 pos($$rstr) = $p + 1;
1250             }
1251             } elsif ($n1 eq 'E' or $n1 eq 'e') {
1252 0 0       0 if ($$rstr =~ m{\G([Ee][+-]?[0-9]+)}gc) {
1253 0         0 $number .= $1;
1254             }
1255             }
1256 738         1340 ($token, $token_desc, $token_type) = ($number, 'NUMBER', 'EXPR');
1257 738 100       1255 if ($prepend) {
1258 2         5 $token = "$prepend$token";
1259 2 50 33     12 pop @tokens if @tokens and $tokens[-1][0] eq $prepend;
1260 2 50 33     9 pop @scope_tokens if @scope_tokens and $scope_tokens[-1][0] eq $prepend;
1261             }
1262 738         1071 next;
1263             }
1264              
1265 7661 100 100     20885 if ($prev_token_type ne 'ARROW' and ($prev_token_type ne 'KEYWORD' or !$c->token_expects_word($prev_token))) {
      100        
1266 5853 100 100     15317 if ($prev_token_type eq 'EXPR' or $prev_token_type eq 'VARIABLE') {
1267 331 100       645 if ($c1 eq 'x') {
1268 5 100       32 if ($$rstr =~ m{\G(x\b(?!\s*=>))}gc){
1269 3         9 ($token, $token_desc, $token_type) = ($1, $1, '');
1270 3         6 next;
1271             }
1272             }
1273             }
1274              
1275 5850 100       16251 if ($c1 eq 'q') {
    100          
    100          
    100          
    100          
1276 212         574 my $quotelike_re = $c->quotelike_re;
1277 212 100       3538 if ($$rstr =~ m{\G((?:$quotelike_re)\b(?!\s*=>))}gc) {
    100          
    50          
    100          
1278 96 50       303 if (my $quotelike = $self->_match_quotelike($c, $rstr, $1)) {
1279 96         190 ($token, $token_desc, $token_type) = ($quotelike, 'STRING', 'STRING');
1280 96         213 next;
1281             } else {
1282 0         0 _debug("QUOTELIKE ERROR: $@") if DEBUG;
1283 0         0 pos($$rstr) = $pos;
1284             }
1285             } elsif ($$rstr =~ m{\G((?:qw)\b(?!\s*=>))}gc) {
1286 98 50       457 if (my $quotelike = $self->_match_quotelike($c, $rstr, $1)) {
1287 98         237 ($token, $token_desc, $token_type) = ($quotelike, 'QUOTED_WORD_LIST', 'EXPR');
1288 98         280 next;
1289             } else {
1290 0         0 _debug("QUOTELIKE ERROR: $@") if DEBUG;
1291 0         0 pos($$rstr) = $pos;
1292             }
1293             } elsif ($$rstr =~ m{\G((?:qx)\b(?!\s*=>))}gc) {
1294 0 0       0 if (my $quotelike = $self->_match_quotelike($c, $rstr, $1)) {
1295 0         0 ($token, $token_desc, $token_type) = ($quotelike, 'BACKTICK', 'EXPR');
1296 0         0 next;
1297             } else {
1298 0         0 _debug("QUOTELIKE ERROR: $@") if DEBUG;
1299 0         0 pos($$rstr) = $pos;
1300             }
1301             } elsif ($$rstr =~ m{\G(qr\b(?!\s*=>))}gc) {
1302 16 50       58 if (my $regexp = $self->_match_regexp($c, $rstr)) {
1303 16         50 ($token, $token_desc, $token_type) = ($regexp, 'qr', 'EXPR');
1304 16         59 next;
1305             } else {
1306 0         0 _debug("QUOTELIKE ERROR: $@") if DEBUG;
1307 0         0 pos($$rstr) = $pos;
1308             }
1309             }
1310             } elsif ($c1 eq 'm') {
1311 663 100       1879 if ($$rstr =~ m{\G(m\b(?!\s*=>))}gc) {
1312 31 50       120 if (my $regexp = $self->_match_regexp($c, $rstr)) {
1313 31         85 ($token, $token_desc, $token_type) = ($regexp, 'm', 'EXPR');
1314 31         65 next;
1315             } else {
1316 0         0 _debug("REGEXP ERROR: $@") if DEBUG;
1317 0         0 pos($$rstr) = $pos;
1318             }
1319             }
1320             } elsif ($c1 eq 's') {
1321 597 100       1667 if ($$rstr =~ m{\G(s\b(?!\s*=>))}gc) {
1322 53 50       202 if (my $regexp = $self->_match_substitute($c, $rstr)) {
1323 53         121 ($token, $token_desc, $token_type) = ($regexp, 's', 'EXPR');
1324 53         93 next;
1325             } else {
1326 0         0 _debug("SUBSTITUTE ERROR: $@") if DEBUG;
1327 0         0 pos($$rstr) = $pos;
1328             }
1329             }
1330             } elsif ($c1 eq 't') {
1331 28 100       105 if ($$rstr =~ m{\G(tr\b(?!\s*=>))}gc) {
1332 3 50       15 if (my $trans = $self->_match_transliterate($c, $rstr)) {
1333 3         8 ($token, $token_desc, $token_type) = ($trans, 'tr', 'EXPR');
1334 3         7 next;
1335             } else {
1336 0         0 _debug("TRANSLITERATE ERROR: $@") if DEBUG;
1337 0         0 pos($$rstr) = $pos;
1338             }
1339             }
1340             } elsif ($c1 eq 'y') {
1341 4 100       19 if ($$rstr =~ m{\G(y\b(?!\s*=>))}gc) {
1342 2 50       9 if (my $trans = $self->_match_transliterate($c, $rstr)) {
1343 2         4 ($token, $token_desc, $token_type) = ($trans, 'y', 'EXPR');
1344 2         4 next;
1345             } else {
1346 0         0 _debug("TRANSLITERATE ERROR: $@") if DEBUG;
1347 0         0 pos($$rstr) = $pos;
1348             }
1349             }
1350             }
1351             }
1352              
1353 7359 100       18126 if ($$rstr =~ m{\G(\w+)}gc) {
1354 6559         11911 $token = $1;
1355 6559 100 66     19352 if ($prev_token_type eq 'ARROW') {
    100 66        
    100          
    100          
1356 521 100       1343 $$rstr =~ m{\G((?:(?:::|')\w+)+)\b}gc and $token .= $1;
1357 521         837 ($token_desc, $token_type) = ('METHOD', 'METHOD');
1358             } elsif ($token eq 'CORE') {
1359 3         5 ($token_desc, $token_type) = ('NAMESPACE', 'WORD');
1360             } elsif ($token eq 'format') {
1361 5 100       29 if ($$rstr =~ m{\G([^=]*?=[ \t]*\n.*?\n\.\n)}gcs) {
1362 4         14 $token .= $1;
1363 4         8 ($token_desc, $token_type) = ('FORMAT', '');
1364 4         7 $current_scope |= F_STATEMENT_END|F_EXPR_END;
1365 4         5 next;
1366             }
1367             } elsif ($c->token_is_keyword($token) and ($prev_token_type ne 'KEYWORD' or !$c->token_expects_word($prev_token) or ($prev_token eq 'sub' and $token eq 'BEGIN'))) {
1368 3817 100       7166 if ($c->token_is_op_keyword($token)) {
1369 164         295 ($token_desc, $token_type) = ($token, 'OP');
1370             } else {
1371 3653         6003 ($token_desc, $token_type) = ('KEYWORD', 'KEYWORD');
1372 3653 100       8415 push @keywords, $token unless $token eq 'undef';
1373             }
1374             } else {
1375 2213 100 100     4421 if ($c1 eq 'v' and $token =~ /^v(?:0|[1-9][0-9]*)$/) {
1376 5 50       31 if ($$rstr =~ m{\G((?:\.[0-9][0-9_]*)+)}gc) {
1377 5         17 $token .= $1;
1378 5         13 ($token_desc, $token_type) = ('VERSION_STRING', 'EXPR');
1379 5         9 next;
1380             }
1381             }
1382 2208 100       6731 $$rstr =~ m{\G((?:(?:::|')\w+)+)\b}gc and $token .= $1;
1383 2208         3624 ($token_desc, $token_type) = ('WORD', 'WORD');
1384 2208 100       3579 if ($prepend) {
1385 49         90 $token = "$prepend$token";
1386 49 100 66     138 pop @tokens if @tokens and $tokens[-1][0] eq $prepend;
1387 49 100 66     166 pop @scope_tokens if @scope_tokens and $scope_tokens[-1][0] eq $prepend;
1388             }
1389             }
1390 6550         9522 next;
1391             }
1392              
1393             # ignore control characters
1394 800 50       1803 if ($$rstr =~ m{\G([[:cntrl:]]+)}gc) {
1395 0         0 next;
1396             }
1397              
1398 800 100       1617 if ($$rstr =~ m{\G([[:ascii:]]+)}gc) {
1399 1 50       3 last if $parent_scope & F_STRING_EVAL;
1400 0         0 _error("UNKNOWN: $1");
1401 0         0 push @{$c->{errors}}, qq{"$1"};
  0         0  
1402 0         0 $token = $1;
1403 0         0 next;
1404             }
1405 799 50       1688 if ($$rstr =~ m{\G([[:^ascii:]](?:[[:^ascii:]]|\w)*)}gc) {
1406 0 0       0 if (!$c->{utf8}) {
1407 0 0       0 last if $parent_scope & F_STRING_EVAL;
1408 0         0 _error("UNICODE?: $1");
1409 0         0 push @{$c->{errors}}, qq{"$1"};
  0         0  
1410             } else {
1411 0         0 _debug("UTF8: $1") if DEBUG;
1412             }
1413 0         0 $token = $1;
1414 0         0 next;
1415             }
1416 799 50       1636 if ($$rstr =~ m{\G(\S+)}gc) {
1417 0 0       0 last if $parent_scope & F_STRING_EVAL;
1418 0         0 _error("UNEXPECTED: $1");
1419 0         0 push @{$c->{errors}}, qq{"$1"};
  0         0  
1420 0         0 $token = $1;
1421             }
1422              
1423 799         1267 last;
1424             } continue {
1425 48418 50       72452 die "Aborted at $prev_pos" if $prev_pos == pos($$rstr);
1426 48418         55552 $prev_pos = pos($$rstr);
1427              
1428 48418 100       67237 if (defined $token) {
1429 28059 100 66     92900 if (!($current_scope & F_EXPR)) {
    100 33        
1430 6317         6885 _debug('BEGIN EXPR') if DEBUG;
1431 6317         8598 $current_scope |= F_EXPR;
1432             } elsif (($current_scope & F_EXPR) and (($current_scope & F_EXPR_END) or ($ends_expr{$token} and $token_type eq 'KEYWORD' and $prev_token ne ',' and $prev_token ne '=>'))) {
1433 3629         5530 @keywords = ();
1434 3629         3938 _debug('END EXPR') if DEBUG;
1435 3629         4464 $current_scope &= MASK_EXPR_END;
1436             }
1437 28059         32664 $prepend = undef;
1438              
1439 28059         29371 if (DEBUG) {
1440             my $token_str = ref $token ? Data::Dump::dump($token) : $token;
1441             _debug("GOT: $token_str ($pos) TYPE: $token_desc ($token_type)".($prev_token_type ? " PREV: $prev_token_type" : '').(@keywords ? " KEYWORD: @keywords" : '').(($current_scope | $parent_scope) & F_EVAL ? ' EVAL' : '').(($current_scope | $parent_scope) & F_KEEP_TOKENS ? ' KEEP' : ''));
1442             }
1443              
1444 28059 100       40016 if ($parent_scope & F_KEEP_TOKENS) {
1445 841         1844 push @scope_tokens, [$token, $token_desc];
1446 841 100 66     2374 if ($token eq '-' or $token eq '+') {
1447 39         47 $prepend = $token;
1448             }
1449             }
1450 28059 100 100     111729 if (!($current_scope & F_KEEP_TOKENS) and (exists $c->{callback}{$token} or exists $c->{keyword}{$token} or exists $c->{sub}{$token}) and $token_type ne 'METHOD' and !$c->token_expects_word($prev_token)) {
      100        
      100        
      100        
1451 1181         1631 $current_scope |= F_KEEP_TOKENS;
1452             }
1453 28059 100       48942 if ($c->token_expects_block($token)) {
1454 1186         1660 $waiting_for_a_block = 1;
1455             }
1456 28059 100 100     58520 if ($current_scope & F_EVAL or ($parent_scope & F_EVAL and (!@{$c->{stack}} or $c->{stack}[-1][0] ne '{'))) {
      100        
      100        
1457 134 100       419 if ($token_type eq 'STRING') {
    100          
    100          
1458 32 100       170 if ($token->[0] =~ /\b(?:(?:use|no)\s+[A-Za-z]|require\s+(?:q[qw]?.|['"])?[A-Za-z])/) {
1459 20         42 my $eval_string = $token->[0];
1460 20 50 33     84 if (defined $eval_string and $eval_string ne '') {
1461 20         40 $eval_string =~ s/\\(.)/$1/g;
1462 20         55 pos($eval_string) = 0;
1463 20         44 $c->{eval} = 1;
1464 20         36 my $saved_stack = $c->{stack};
1465 20         70 $c->{stack} = [];
1466 20         32 eval { $self->_scan($c, \$eval_string, (
  20         241  
1467             ($current_scope | $parent_scope | F_STRING_EVAL) &
1468             F_RESCAN
1469             ))};
1470 20         58 $c->{stack} = $saved_stack;
1471             }
1472             }
1473 32         49 $current_scope &= MASK_EVAL;
1474             } elsif ($token_desc eq 'HEREDOC') {
1475 1 50       6 if ($token->[0] =~ /\b(?:use|require|no)\s+[A-Za-z]/) {
1476 1         3 my $eval_string = $token->[0];
1477 1 50 33     4 if (defined $eval_string and $eval_string ne '') {
1478 1         3 $eval_string =~ s/\\(.)/$1/g;
1479 1         2 pos($eval_string) = 0;
1480 1         3 $c->{eval} = 1;
1481 1         2 my $saved_stack = $c->{stack};
1482 1         2 $c->{stack} = [];
1483 1         2 eval { $self->_scan($c, \$eval_string, (
  1         28  
1484             ($current_scope | $parent_scope | F_STRING_EVAL) &
1485             F_RESCAN
1486             ))};
1487 1         3 $c->{stack} = $saved_stack;
1488             }
1489             }
1490 1         2 $current_scope &= MASK_EVAL;
1491             } elsif ($token_type eq 'VARIABLE') {
1492 8         29 $current_scope &= MASK_EVAL;
1493             }
1494 134 100       287 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
1495             }
1496 28059 100       41323 if ($token eq 'eval') {
1497 51         123 $current_scope |= F_EVAL;
1498 51         93 $c->{eval} = 1;
1499             }
1500              
1501 28059 100       39955 if ($current_scope & F_KEEP_TOKENS) {
1502 4847         10131 push @tokens, [$token, $token_desc];
1503 4847 100 100     11951 if ($token eq '-' or $token eq '+') {
1504 12         19 $prepend = $token;
1505             }
1506 4847 100 100     9427 if ($token_type eq 'KEYWORD' and $has_sideff{$token}) {
1507 11         21 $current_scope |= F_SIDEFF;
1508             }
1509             }
1510 28059 100       40093 if ($stack) {
1511 2342         2900 push @{$c->{stack}}, $stack;
  2342         4373  
1512 2342         2865 _dump_stack($c, $stack->[0]) if DEBUG;
1513 2342         3245 my $child_scope = $current_scope | $parent_scope;
1514 2342 100 100     5514 if ($token eq '{' and $is_conditional{$stack->[2]}) {
1515 271         394 $child_scope |= F_CONDITIONAL
1516             }
1517 2342         18105 my $scanned_tokens = $self->_scan($c, $rstr, (
1518             $child_scope & F_RESCAN
1519             ));
1520 2342 100 100     5620 if ($token eq '{' and $current_scope & F_EVAL) {
1521 16         25 $current_scope &= MASK_EVAL;
1522 16 50       47 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
1523             }
1524 2342 100       4709 if ($current_scope & F_KEEP_TOKENS) {
    100          
1525 139   50     323 my $start = pop @tokens || '';
1526 139   50     359 my $end = pop @$scanned_tokens || '';
1527 139         549 push @tokens, [$scanned_tokens, "$start->[0]$end->[0]"];
1528             } elsif ($parent_scope & F_KEEP_TOKENS) {
1529 36   50     81 my $start = pop @scope_tokens || '';
1530 36   50     67 my $end = pop @$scanned_tokens || '';
1531 36         142 push @scope_tokens, [$scanned_tokens, "$start->[0]$end->[0]"];
1532             }
1533              
1534 2342 100 100     7194 if ($stack->[0] eq '(' and $prev_token_type eq 'KEYWORD' and @keywords and $keywords[-1] eq $prev_token and !$c->token_expects_expr_block($prev_token)) {
      100        
      66        
      100        
1535 305         431 pop @keywords;
1536             }
1537              
1538 2342 100 100     5843 if ($stack->[0] eq '{' and @keywords and $c->token_expects_block($keywords[0]) and !$c->token_expects_block_list($keywords[-1])) {
      100        
      100        
1539 663 50 0     1473 $current_scope |= F_STATEMENT_END unless @tokens and ($c->token_defines_sub($keywords[-1]) or $keywords[-1] eq 'eval');
      33        
1540             }
1541 2342         4351 $stack = undef;
1542             }
1543 28059 100       39793 if ($current_scope & F_STATEMENT_END) {
1544 4658 100 66     8990 if (($current_scope & F_KEEP_TOKENS) and @tokens) {
1545 1119         1915 my $first_token = $tokens[0][0];
1546 1119 100       2103 if ($first_token eq '->') {
1547 46         102 $first_token = $tokens[1][0];
1548             # ignore ->use and ->no
1549             # ->require may be from UNIVERSAL::require
1550 46 100 66     252 if ($first_token eq 'use' or $first_token eq 'no') {
1551 1         2 $first_token = '';
1552             }
1553             }
1554 1119 100       2369 my $cond = (($current_scope | $parent_scope) & (F_CONDITIONAL|F_SIDEFF)) ? 1 : 0;
1555 1119 100       2203 if (exists $c->{callback}{$first_token}) {
1556 849         1673 $c->{current_scope} = \$current_scope;
1557 849         1504 $c->{cond} = $cond;
1558 849         2865 $c->{callback}{$first_token}->($c, $rstr, \@tokens);
1559              
1560 849 50 33     2216 if ($c->{found_unsupported_package} and !$c->{quick}) {
1561 0         0 my $unsupported = $c->{found_unsupported_package};
1562 0         0 $c->{quick} = 1;
1563 0         0 $self->_skim_string($c, $rstr);
1564 0         0 warn "Unsupported package '$unsupported' is found. Result may be incorrect.\n";
1565             }
1566             }
1567 1119 100       2477 if (exists $c->{keyword}{$first_token}) {
1568 224         444 $c->{current_scope} = \$current_scope;
1569 224         390 $c->{cond} = $cond;
1570 224         419 $tokens[0][1] = 'KEYWORD';
1571 224         570 $c->run_callback_for(keyword => $first_token, \@tokens);
1572             }
1573 1119 100 66     4353 if (exists $c->{method}{$first_token} and $caller_package) {
1574 18         87 unshift @tokens, [$caller_package, 'WORD'];
1575 18         42 $c->{current_scope} = \$current_scope;
1576 18         30 $c->{cond} = $cond;
1577 18         47 $c->run_callback_for(method => $first_token, \@tokens);
1578             }
1579 1119 100       3415 if ($current_scope & F_SIDEFF) {
1580 11         26 $current_scope &= MASK_SIDEFF;
1581 11         53 while(my $token = shift @tokens) {
1582 58 100       156 last if $has_sideff{$token->[0]};
1583             }
1584 11 100       30 $current_scope &= F_SIDEFF if grep {$has_sideff{$_->[0]}} @tokens;
  46         254  
1585 11 50       28 if (@tokens) {
1586 11         25 $first_token = $tokens[0][0];
1587 11 100       64 $cond = (($current_scope | $parent_scope) & (F_CONDITIONAL|F_SIDEFF)) ? 1 : 0;
1588 11 50       63 if (exists $c->{callback}{$first_token}) {
1589 0         0 $c->{current_scope} = \$current_scope;
1590 0         0 $c->{cond} = $cond;
1591 0         0 $c->{callback}{$first_token}->($c, $rstr, \@tokens);
1592             }
1593 11 100       53 if (exists $c->{keyword}{$first_token}) {
1594 1         3 $c->{current_scope} = \$current_scope;
1595 1         3 $c->{cond} = $cond;
1596 1         3 $tokens[0][1] = 'KEYWORD';
1597 1         5 $c->run_callback_for(keyword => $first_token, \@tokens);
1598             }
1599 11 50 33     87 if (exists $c->{method}{$first_token} and $caller_package) {
1600 0         0 unshift @tokens, [$caller_package, 'WORD'];
1601 0         0 $c->{current_scope} = \$current_scope;
1602 0         0 $c->{cond} = $cond;
1603 0         0 $c->run_callback_for(method => $first_token, \@tokens);
1604             }
1605             }
1606             }
1607             }
1608 4658         6979 @tokens = ();
1609 4658         5600 @keywords = ();
1610 4658         5469 $current_scope &= MASK_STATEMENT_END;
1611 4658         5320 $caller_package = undef;
1612 4658         6368 $token = $token_type = '';
1613 4658         5016 _debug('END SENTENSE') if DEBUG;
1614             }
1615 28059 100 100     43126 if ($unstack and @{$c->{stack}}) {
  2268         5225  
1616 2246         2545 my $stacked = pop @{$c->{stack}};
  2246         3778  
1617 2246         4116 my $stacked_type = substr($stacked->[0], -1);
1618 2246 50 66     11175 if (
      66        
      33        
      66        
      33        
1619             ($unstack eq '}' and $stacked_type ne '{') or
1620             ($unstack eq ']' and $stacked_type ne '[') or
1621             ($unstack eq ')' and $stacked_type ne '(')
1622             ) {
1623 0   0     0 my $prev_pos = $stacked->[1] || 0;
1624 0         0 die "mismatch $stacked_type $unstack\n" .
1625             substr($$rstr, $prev_pos, pos($$rstr) - $prev_pos);
1626             }
1627 2246         2568 _dump_stack($c, $unstack) if DEBUG;
1628 2246         2847 $current_scope |= F_SCOPE_END;
1629 2246         2889 $unstack = undef;
1630             }
1631              
1632 28059 100       40164 last if $current_scope & F_SCOPE_END;
1633 25740 100       38391 last if $c->{ended};
1634 25635 50 33     40634 last if $c->{last_found_by_skimming} and $c->{last_found_by_skimming} < pos($$rstr);
1635              
1636 25635         37285 ($prev_token, $prev_token_type) = ($token, $token_type);
1637             }
1638              
1639 45994 50 33     49235 if (@{$c->{errors}} and !($parent_scope & F_STRING_EVAL)) {
  45994         100272  
1640 0         0 my $rest = substr($$rstr, pos($$rstr));
1641 0 0       0 _error("REST:\n\n".$rest) if $rest;
1642 0         0 last;
1643             }
1644             }
1645              
1646 3225 100       5074 if (@tokens) {
1647 41 50       126 if (my $first_token = $tokens[0][0]) {
1648 41 100       98 if (exists $c->{callback}{$first_token}) {
1649 28         88 $c->{callback}{$first_token}->($c, $rstr, \@tokens);
1650             }
1651 41 100       145 if (exists $c->{keyword}{$first_token}) {
1652 10         21 $tokens[0][1] = 'KEYWORD';
1653 10         25 $c->run_callback_for(keyword => $first_token, \@tokens);
1654             }
1655             }
1656             }
1657              
1658 3225         3697 _dump_stack($c, "END SCOPE") if DEBUG;
1659              
1660 3225         8276 \@scope_tokens;
1661             }
1662              
1663             sub _match_quotelike {
1664 194     194   621 my ($self, $c, $rstr, $op) = @_;
1665              
1666             # '#' only works when it comes just after the op,
1667             # without prepending spaces
1668 194         2941 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1669              
1670 194 50       701 unless ($$rstr =~ m/\G(\S)/gc) {
1671 0         0 return _match_error($rstr, "No block delimiter found after $op");
1672             }
1673 194         369 my $ldel = $1;
1674 194         344 my $startpos = pos($$rstr);
1675              
1676 194 100       582 if ($ldel =~ /[[(<{]/) {
1677 141         412 my ($rdel, $re_skip) = _gen_rdel_and_re_skip($ldel);
1678 141         331 my @nest = ($ldel);
1679 141         211 my ($p, $c1);
1680 141         333 while(defined($p = pos($$rstr))) {
1681 372         585 $c1 = substr($$rstr, $p, 1);
1682 372 100       615 if ($c1 eq '\\') {
1683 28         64 pos($$rstr) = $p + 2;
1684 28         55 next;
1685             }
1686 344 100       615 if ($c1 eq $ldel) {
1687 15         29 pos($$rstr) = $p + 1;
1688 15         31 push @nest, $ldel;
1689 15         26 next;
1690             }
1691 329 100       606 if ($c1 eq $rdel) {
1692 156         323 pos($$rstr) = $p + 1;
1693 156         289 pop @nest;
1694 156 100       370 last unless @nest;
1695 15         49 next;
1696             }
1697 173 50       1713 $$rstr =~ m{\G$re_skip}gc and next;
1698 0         0 last;
1699             }
1700 141 50       364 return if @nest;
1701             } else {
1702 53         166 my $re = _gen_re_str_in_delims_with_end_delim($ldel);
1703 53 50       1217 $$rstr =~ /\G$re/gcs or return;
1704             }
1705              
1706 194         342 my $endpos = pos($$rstr);
1707              
1708 194         857 return [substr($$rstr, $startpos, $endpos - $startpos - 1), $op];
1709             }
1710              
1711             sub _match_regexp0 { # //
1712 98     98   242 my ($self, $c, $rstr, $startpos, $token_type) = @_;
1713 98         223 pos($$rstr) = $startpos + 1;
1714              
1715 98         265 my $re_shortcut = _gen_re_regexp_shortcut('/');
1716 98 100 100     1387 $$rstr =~ m{\G$re_shortcut}gcs or # shortcut
    100          
1717             defined($self->_scan_re($c, $rstr, '/', '/', $token_type ? 'm' : '')) or return _match_error($rstr, "Closing delimiter was not found: $@");
1718              
1719 97         301 $$rstr =~ m/\G([msixpodualgc]*)/gc;
1720 97         203 my $mod = $1;
1721              
1722 97         145 my $endpos = pos($$rstr);
1723              
1724 97         190 my $re = substr($$rstr, $startpos, $endpos - $startpos);
1725 97 100 100     300 if ($re =~ /\n/s and $mod !~ /x/) {
1726 1         5 return _match_error($rstr, "multiline without x");
1727             }
1728 96         290 return $re;
1729             }
1730              
1731             sub _match_regexp {
1732 47     47   103 my ($self, $c, $rstr) = @_;
1733 47   50     128 my $startpos = pos($$rstr) || 0;
1734              
1735             # '#' only works when it comes just after the op,
1736             # without prepending spaces
1737 47         818 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1738              
1739 47 50       176 unless ($$rstr =~ m/\G(\S)/gc) {
1740 0         0 return _match_error($rstr, "No block delimiter found");
1741             }
1742 47         157 my ($ldel, $rdel) = ($1, $1);
1743              
1744 47 100       189 if ($ldel =~ /[[(<{]/) {
1745 27         62 $rdel =~ tr/[({/;
1746             }
1747              
1748 47         134 my $re_shortcut = _gen_re_regexp_shortcut($ldel, $rdel);
1749 47 50 66     1851 $$rstr =~ m{\G$re_shortcut}gcs or # shortcut
1750             defined($self->_scan_re($c, $rstr, $ldel, $rdel, 'm/qr')) or return _match_error($rstr, "Closing delimiter was not found: $@");
1751              
1752             # strictly speaking, qr// doesn't support gc.
1753 47         186 $$rstr =~ m/\G[msixpodualgc]*/gc;
1754 47         82 my $endpos = pos($$rstr);
1755              
1756 47         216 return substr($$rstr, $startpos, $endpos - $startpos);
1757             }
1758              
1759             sub _match_substitute {
1760 53     53   100 my ($self, $c, $rstr) = @_;
1761 53   50     106 my $startpos = pos($$rstr) || 0;
1762              
1763             # '#' only works when it comes just after the op,
1764             # without prepending spaces
1765 53         801 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1766              
1767 53 50       208 unless ($$rstr =~ m/\G(\S)/gc) {
1768 0         0 return _match_error($rstr, "No block delimiter found");
1769             }
1770 53         176 my ($ldel1, $rdel1) = ($1, $1);
1771              
1772 53 100       146 if ($ldel1 =~ /[[(<{]/) {
1773 22         40 $rdel1 =~ tr/[({/;
1774             }
1775              
1776 53         120 my $re_shortcut = _gen_re_regexp_shortcut($ldel1, $rdel1);
1777 53 50 100     1585 ($ldel1 ne '\\' and $$rstr =~ m{\G$re_shortcut}gcs) or # shortcut
      66        
1778             defined($self->_scan_re($c, $rstr, $ldel1, $rdel1, 's')) or return _match_error($rstr, "Closing delimiter was not found: $@");
1779 53 50       217 defined($self->_scan_re2($c, $rstr, $ldel1, 's')) or return;
1780 53         142 $$rstr =~ m/\G[msixpodualgcer]*/gc;
1781 53         210 my $endpos = pos($$rstr);
1782              
1783 53         168 return substr($$rstr, $startpos, $endpos - $startpos);
1784             }
1785              
1786             sub _match_transliterate {
1787 5     5   13 my ($self, $c, $rstr) = @_;
1788 5   50     15 my $startpos = pos($$rstr) || 0;
1789              
1790             # '#' only works when it comes just after the op,
1791             # without prepending spaces
1792 5         169 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1793              
1794 5 50       27 unless ($$rstr =~ m/\G(\S)/gc) {
1795 0         0 return _match_error($rstr, "No block delimiter found");
1796             }
1797 5         16 my $ldel1 = $1;
1798 5         7 my $ldel2;
1799              
1800 5 100       17 if ($ldel1 =~ /[[(<{]/) {
1801 1         3 (my $rdel1 = $ldel1) =~ tr/[({/;
1802 1         3 my $re = _gen_re_str_in_delims_with_end_delim($rdel1);
1803 1 50       33 $$rstr =~ /\G$re/gcs or return;
1804 1         33 $$rstr =~ /\G(?:$re_comment)/gcs;
1805 1 50       5 unless ($$rstr =~ /\G\s*(\S)/gc) {
1806 0         0 return _match_error($rstr, "Missing second block");
1807             }
1808 1         3 $ldel2 = $1;
1809             } else {
1810 4         16 my $re = _gen_re_str_in_delims_with_end_delim($ldel1);
1811 4 50       186 $$rstr =~ /\G$re/gcs or return;
1812 4         15 $ldel2 = $ldel1;
1813             }
1814              
1815 5 100       16 if ($ldel2 =~ /[[(<{]/) {
1816 1         4 (my $rdel2 = $ldel2) =~ tr/[({/;
1817 1         7 my $re = _gen_re_str_in_delims_with_end_delim($rdel2);
1818 1 50       64 $$rstr =~ /\G$re/gcs or return;
1819             } else {
1820 4         12 my $re = _gen_re_str_in_delims_with_end_delim($ldel2);
1821 4 50       123 $$rstr =~ /\G$re/gcs or return;
1822             }
1823              
1824 5         20 $$rstr =~ m/\G[cdsr]*/gc;
1825 5         11 my $endpos = pos($$rstr);
1826              
1827 5         25 return substr($$rstr, $startpos, $endpos - $startpos);
1828             }
1829              
1830             sub _match_heredoc {
1831 16     16   36 my ($self, $c, $rstr) = @_;
1832              
1833 16   50     44 my $startpos = pos($$rstr) || 0;
1834              
1835 16         49 $$rstr =~ m{\G(?:<<(~)?\s*)}gc;
1836 16 100       52 my $indent = $1 ? "\\s*" : "";
1837              
1838 16         25 my $label;
1839 16 100       564 if ($$rstr =~ m{\G\\?([A-Za-z_]\w*)}gc) {
    50          
1840 8         15 $label = $1;
1841             } elsif ($$rstr =~ m{
1842             \G ' ($re_str_in_single_quotes) '
1843             | \G " ($re_str_in_double_quotes) "
1844             | \G ` ($re_str_in_backticks) `
1845             }gcsx) {
1846 8         26 $label = $+;
1847             } else {
1848 0         0 return;
1849             }
1850 16         38 $label =~ s/\\(.)/$1/g;
1851 16         24 my $extrapos = pos($$rstr);
1852 16         50 $$rstr =~ m{\G.*\n}gc;
1853 16         68 my $str1pos = pos($$rstr)--;
1854 16 100       411 unless ($$rstr =~ m{\G.*?\n$indent(?=\Q$label\E\n)}gcs) {
1855 2         8 return _match_error($rstr, qq{Missing here doc terminator ('$label')});
1856             }
1857 14         27 my $ldpos = pos($$rstr);
1858 14         136 $$rstr =~ m{\G\Q$label\E\n}gc;
1859 14         162 my $ld2pos = pos($$rstr);
1860              
1861 14         80 my $heredoc = [
1862             substr($$rstr, $str1pos, $ldpos-$str1pos),
1863             substr($$rstr, $startpos, $extrapos-$startpos),
1864             substr($$rstr, $ldpos, $ld2pos-$ldpos),
1865             ];
1866 14         80 substr($$rstr, $str1pos, $ld2pos - $str1pos) = '';
1867 14         38 pos($$rstr) = $extrapos;
1868 14 100       36 if ($indent) {
1869 1         4 $c->add_perl('5.026', '<<~');
1870             }
1871 14         48 return $heredoc;
1872             }
1873              
1874             sub _scan_re {
1875 126     126   390 my ($self, $c, $rstr, $ldel, $rdel, $op) = @_;
1876 126   50     271 my $startpos = pos($$rstr) || 0;
1877              
1878 126         187 _debug(" L $ldel R $rdel") if DEBUG_RE;
1879              
1880 126         193 my ($outer_opening_delimiter, $outer_closing_delimiter);
1881 126 100       170 if (@{$c->{stack}}) {
  126         335  
1882 110         319 ($outer_closing_delimiter = $outer_opening_delimiter = $c->{stack}[-1][0]) =~ tr/[({/;
1883             }
1884              
1885 126         304 my @nesting = ($ldel);
1886 126         170 my $multiline = 0;
1887 126         167 my $saw_sharp = 0;
1888 126         163 my $prev;
1889 126         177 my ($p, $c1);
1890 126         286 while (defined($p = pos($$rstr))) {
1891 5053         6436 $c1 = substr($$rstr, $p, 1);
1892 5053 100       7064 if ($c1 eq "\n") {
1893 271         470 $$rstr =~ m{\G\n\s*}gcs;
1894 271         314 $multiline = 1;
1895 271         294 $saw_sharp = 0;
1896             # _debug("CRLF") if DEBUG_RE;
1897 271         385 next;
1898             }
1899 4782 100 66     10131 if ($c1 eq ' ' or $c1 eq "\t") {
1900 696         1024 $$rstr =~ m{\G\s*}gc;
1901             # _debug("WHITESPACE") if DEBUG_RE;
1902 696         1082 next;
1903             }
1904 4086 100 100     6497 if ($c1 eq '#' and $rdel ne '#') {
1905 144 100 100     800 if ($multiline and $$rstr =~ m{\G(#[^\Q$rdel\E]*?)\n}gcs) {
1906 94         119 _debug(" comment $1") if DEBUG_RE
1907             } else {
1908 50         95 pos($$rstr) = $p + 1;
1909 50         69 $saw_sharp = 1;
1910 50         55 _debug(" saw #") if DEBUG_RE;
1911             }
1912 144         215 next;
1913             }
1914              
1915 3942 100 100     6140 if ($c1 eq '\\' and $rdel ne '\\') {
1916 416 50       924 if ($$rstr =~ m/\G(\\.)/gcs) {
1917 416         478 _debug(" escaped $1") if DEBUG_RE;
1918 416         773 next;
1919             }
1920             }
1921              
1922 3526         3762 _debug(" looking @nesting: $c1") if DEBUG_RE;
1923              
1924 3526 100       4815 if ($c1 eq '[') {
1925             # character class may have other (ignorable) delimiters
1926 197 50       534 if ($$rstr =~ m/\G(\[\[:\w+?:\]\])/gcs) {
1927 0         0 _debug(" character class $1") if DEBUG_RE;
1928 0         0 next;
1929             }
1930 197 100       646 if ($$rstr =~ m/\G(\[[^\\\]]]*?(\\.[^\\\]]]*)*\])/gcs) {
1931 59         83 _debug(" character class: $1") if DEBUG_RE;
1932 59         103 next;
1933             }
1934             }
1935              
1936 3467 100       5695 if ($c1 eq $rdel) {
    100          
1937 156         339 pos($$rstr) = $p + 1;
1938 156 100       319 if ($saw_sharp) {
1939 39         50 my $tmp_pos = $p + 1;
1940 39 100       63 if ($op eq 's') {
1941 3         4 _debug(" looking for latter part") if DEBUG_RE;
1942 3         11 my $latter = $self->_scan_re2($c, $rstr, $ldel, $op);
1943 3 50       8 if (!defined $latter) {
1944 0         0 pos($$rstr) = $tmp_pos;
1945 0         0 next;
1946             }
1947 3         4 _debug(" latter: $latter") if DEBUG_RE;
1948             }
1949 39 100       122 if ($$rstr =~ m/\G[a-wyz]*x/) {
1950             # looks like an end of block
1951 2         4 _debug(" end of block $rdel (after #)") if DEBUG_RE;
1952 2         6 @nesting = ();
1953 2         4 pos($$rstr) = $tmp_pos;
1954 2         5 last;
1955             }
1956 37         54 pos($$rstr) = $tmp_pos;
1957 37 100       59 if ($multiline) {
1958 29         46 next; # part of a comment
1959             }
1960             }
1961 125         186 _debug(" end of block $rdel") if DEBUG_RE;
1962 125         182 my $expected = $rdel;
1963 125 100       298 if ($ldel ne $rdel) {
1964 44         76 $expected =~ tr/)}]>/({[
1965             }
1966 125         373 while(my $nested = pop @nesting) {
1967 129 100       291 last if $nested eq $expected;
1968             }
1969 125 100       283 last unless @nesting;
1970 2         4 next;
1971             } elsif ($c1 eq $ldel) {
1972 30         42 pos($$rstr) = $p + 1;
1973 30 100 66     66 if ($multiline and $saw_sharp) {
1974             } else {
1975 2         2 _debug(" block $ldel") if DEBUG_RE;
1976 2         5 push @nesting, $ldel;
1977 2         3 next;
1978             }
1979             }
1980              
1981 3309 100       4646 if ($c1 eq '{') {
1982             # quantifier shouldn't be nested
1983 45 100       137 if ($$rstr =~ m/\G(\{[0-9]+(?:,(?:[0-9]+)?)?})/gcs) {
1984 4         6 _debug(" quantifier $1") if DEBUG_RE;
1985 4         10 next;
1986             }
1987             }
1988              
1989 3305 100       4554 if ($c1 eq '(') {
1990 407         609 my $c2 = substr($$rstr, $p + 1, 1);
1991 407 100 100     1101 if ($c2 eq '?' and !($multiline and $saw_sharp)) {
      100        
1992             # code
1993 209 100       595 if ($$rstr =~ m/\G((\()\?+?)(?=\{)/gc) {
1994 70         78 _debug(" code $1") if DEBUG_RE;
1995 70         121 push @nesting, $2;
1996 70 50       95 unless (eval { $self->_scan($c, $rstr, F_EXPECTS_BRACKET); 1 }) {
  70         172  
  70         128  
1997 0         0 _debug("scan failed") if DEBUG_RE;
1998 0         0 return;
1999             }
2000 70         266 next;
2001             }
2002             # comment
2003 139 100       272 if ($$rstr =~ m{\G(\(\?\#[^\\\)]*(?:\\.[^\\\)]*)*\))}gcs) {
2004 10         11 _debug(" comment $1") if DEBUG_RE;
2005 10         15 next;
2006             }
2007             }
2008              
2009             # grouping may have (ignorable) <>
2010 327 50       850 if ($$rstr =~ m/\G((\()(?:<[!=]|<\w+?>|>)?)/gc) {
2011 327         355 _debug(" group $1") if DEBUG_RE;
2012 327         685 push @nesting, $2;
2013 327         562 next;
2014             }
2015             }
2016              
2017             # maybe variables (maybe not)
2018 2898 100 100     4592 if ($c1 eq '$' and substr($$rstr, $p + 1, 1) eq '{') {
2019 3         7 my @tmp_stack = @{$c->{stack}};
  3         12  
2020 3 50       7 next if eval { $self->_scan($c, $rstr, F_EXPECTS_BRACKET); 1 };
  3         25  
  3         15  
2021 0         0 pos($$rstr) = $p;
2022 0         0 $c->{stack} = \@tmp_stack;
2023             }
2024              
2025 2895 100       4086 if ($c1 eq ')') {
2026 397 100 66     1000 if (@nesting and $nesting[-1] eq '(') {
2027 393         444 _debug(" end of group $c1") if DEBUG_RE;
2028 393         498 pop @nesting;
2029 393         825 pos($$rstr) = $p + 1;
2030 393         710 next;
2031             } else {
2032             # die "unnested @nesting" unless $saw_sharp;
2033             }
2034             }
2035              
2036             # for //, see if an outer closing delimiter is found first (ie. see if it was actually a /)
2037 2502 100       3515 if (!$op) {
2038 87 100 66     168 if ($outer_opening_delimiter and $c1 eq $outer_opening_delimiter) {
2039 1         1 push @nesting, $c1;
2040 1         3 pos($$rstr) = $p + 1;
2041 1         3 next;
2042             }
2043              
2044 86 100 66     173 if ($outer_closing_delimiter and $c1 eq $outer_closing_delimiter) {
2045 2 100 66     7 if (@nesting and $nesting[-1] eq $outer_opening_delimiter) {
2046 1         2 pop @nesting;
2047 1         3 pos($$rstr) = $p + 1;
2048 1         2 next;
2049             }
2050              
2051 1         4 return _match_error($rstr, "Outer closing delimiter: $outer_closing_delimiter is found");
2052             }
2053             }
2054              
2055 2499 50       4780 if ($$rstr =~ m/\G(\w+|.)/gcs) {
2056 2499         2693 _debug(" rest $1") if DEBUG_RE;
2057 2499         3887 next;
2058             }
2059 0         0 last;
2060             }
2061 125 50       265 if ($#nesting>=0) {
2062 0         0 return _match_error($rstr, "Unmatched opening bracket(s): ". join("..",@nesting)."..");
2063             }
2064              
2065 125         196 my $endpos = pos($$rstr);
2066              
2067 125         662 return substr($$rstr, $startpos, $endpos - $startpos);
2068             }
2069              
2070              
2071             sub _scan_re2 {
2072 56     56   133 my ($self, $c, $rstr, $ldel, $op) = @_;
2073 56         110 my $startpos = pos($$rstr);
2074              
2075 56 100       150 if ($ldel =~ /[[(<{]/) {
2076 23         158 $$rstr =~ /\G(?:$re_comment)/gcs;
2077              
2078 23 50       68 unless ($$rstr =~ /\G\s*(\S)/gc) {
2079 0         0 return _match_error($rstr, "Missing second block for quotelike $op");
2080             }
2081 23         44 $ldel = $1;
2082             }
2083              
2084 56 100       129 if ($ldel =~ /[[(<{]/) {
2085 23         63 my ($rdel, $re_skip) = _gen_rdel_and_re_skip($ldel);
2086 23         41 my @nest = $ldel;
2087 23         27 my ($p, $c1);
2088 23         47 while(defined($p = pos($$rstr))) {
2089 168         207 $c1 = substr($$rstr, $p, 1);
2090 168 100       222 if ($c1 eq '\\') {
2091 16         23 pos($$rstr) = $p + 2;
2092 16         27 next;
2093             }
2094 152 100       198 if ($c1 eq $ldel) {
2095 25         31 pos($$rstr) = $p + 1;
2096 25         36 push @nest, $ldel;
2097 25         36 next;
2098             }
2099 127 100       180 if ($c1 eq $rdel) {
2100 48         65 pos($$rstr) = $p + 1;
2101 48         66 pop @nest;
2102 48 100       75 last unless @nest;
2103 25         35 next;
2104             }
2105 79 50       318 $$rstr =~ m{\G$re_skip}gc and next;
2106 0         0 last;
2107             }
2108 23 50       46 return _match_error($rstr, "nesting mismatch: @nest") if @nest;
2109             } else {
2110 33         85 my $re = _gen_re_str_in_delims_with_end_delim($ldel);
2111 33 50       554 $$rstr =~ /\G$re/gcs or return;
2112             }
2113              
2114 56         101 my $endpos = pos($$rstr);
2115              
2116 56         173 return substr($$rstr, $startpos, $endpos - $startpos);
2117             }
2118              
2119             sub _use {
2120 776     776   1579 my ($c, $rstr, $tokens) = @_;
2121 776         917 _debug("USE TOKENS: ".(Data::Dump::dump($tokens))) if DEBUG;
2122 776         1236 shift @$tokens; # discard 'use' itself
2123              
2124             # TODO: see if the token is WORD or not?
2125 776 50       1997 my $name_token = shift @$tokens or return;
2126 776         1351 my $name = $name_token->[0];
2127 776 50 33     3237 return if !defined $name or ref $name or $name eq '';
      33        
2128              
2129 776         1575 my $c1 = substr($name, 0, 1);
2130 776 100       1535 if ($c1 eq '5') {
2131 3         13 $c->add(perl => $name);
2132 3         259 return;
2133             }
2134 773 100       1514 if ($c1 eq 'v') {
2135 6         15 my $c2 = substr($name, 1, 1);
2136 6 100       27 if ($c2 eq '5') {
2137 1         3 $c->add(perl => $name);
2138 1         84 return;
2139             }
2140 5 50       14 if ($c2 eq '6') {
2141 0         0 $c->{perl6} = 1;
2142 0         0 $c->{ended} = 1;
2143 0         0 return;
2144             }
2145             }
2146 772 100       2040 if ($c->enables_utf8($name)) {
2147 18         45 $c->add($name => 0);
2148 18         443 $c->{utf8} = 1;
2149 18 100       53 if (!$c->{decoded}) {
2150 9         16 $c->{decoded} = 1;
2151 9         12 _debug("UTF8 IS ON") if DEBUG;
2152 9         109 utf8::decode($$rstr);
2153 9         27 pos($$rstr) = 0;
2154 9         29 $c->{ended} = $c->{redo} = 1;
2155             }
2156             }
2157              
2158 772 50       2422 if (is_module_name($name)) {
2159 772         1292 my $maybe_version_token = $tokens->[0];
2160 772         1214 my $maybe_version_token_desc = $maybe_version_token->[1];
2161 772 100 66     3486 if ($maybe_version_token_desc and ($maybe_version_token_desc eq 'NUMBER' or $maybe_version_token_desc eq 'VERSION_STRING')) {
      100        
2162 34         128 $c->add($name => $maybe_version_token->[0]);
2163 34         2953 shift @$tokens;
2164             } else {
2165 738         1972 $c->add($name => 0);
2166             }
2167              
2168 772 100       32475 if (exists $sub_keywords{$name}) {
2169 5         7 $c->register_sub_keywords(@{$sub_keywords{$name}});
  5         18  
2170 5         24 $c->prototype_re(qr{\G(\((?:[^\\\(\)]*(?:\\.[^\\\(\)]*)*)\))});
2171             }
2172 772 100       2045 if (exists $filter_modules{$name}) {
2173 1         2 my $tmp = pos($$rstr);
2174 1         3 my $redo = $filter_modules{$name}->($rstr);
2175 1         2 pos($$rstr) = $tmp;
2176 1 50       3 $c->{ended} = $c->{redo} = 1 if $redo;
2177             }
2178             }
2179              
2180 772 100       1930 if ($c->has_callback_for(use => $name)) {
    100          
2181 411         685 eval { $c->run_callback_for(use => $name, $tokens) };
  411         947  
2182 411 50       2603 warn "Callback Error: $@" if $@;
2183             } elsif ($name =~ /\b(?:Mo[ou]se?X?|MooX?|Elk|Antlers|Role)\b/) {
2184 3 50       12 my $module = $name =~ /Role/ ? 'Moose::Role' : 'Moose';
2185 3 100       9 if ($c->has_callback_for(use => $module)) {
2186 1         2 eval { $c->run_callback_for(use => $module, $tokens) };
  1         4  
2187 1 50       3 warn "Callback Error: $@" if $@;
2188             }
2189             }
2190              
2191 772 50       2520 if (exists $unsupported_packages{$name}) {
2192 0         0 $c->{found_unsupported_package} = $name;
2193             }
2194             }
2195              
2196             sub _require {
2197 69     69   142 my ($c, $rstr, $tokens) = @_;
2198 69         82 _debug("REQUIRE TOKENS: ".(Data::Dump::dump($tokens))) if DEBUG;
2199 69         107 shift @$tokens; # discard 'require' itself
2200              
2201             # TODO: see if the token is WORD or not?
2202 69 50       184 my $name_token = shift @$tokens or return;
2203 69         125 my $name = $name_token->[0];
2204 69 100       136 if (ref $name) {
2205 7         11 $name = $name->[0];
2206 7 100       37 return if $name =~ /\.pl$/i;
2207              
2208 5         18 $name =~ s|/|::|g;
2209 5         14 $name =~ s|\.pm$||i;
2210             }
2211 67 50 33     220 return if !defined $name or $name eq '';
2212              
2213 67         119 my $c1 = substr($name, 0, 1);
2214 67 100       143 if ($c1 eq '5') {
2215 1         3 $c->add_conditional(perl => $name);
2216 1         75 return;
2217             }
2218 66 100       129 if ($c1 eq 'v') {
2219 1         2 my $c2 = substr($name, 1, 1);
2220 1 50       3 if ($c2 eq '5') {
2221 1         3 $c->add_conditional(perl => $name);
2222 1         95 return;
2223             }
2224 0 0       0 if ($c2 eq '6') {
2225 0         0 $c->{perl6} = 1;
2226 0         0 $c->{ended} = 1;
2227 0         0 return;
2228             }
2229             }
2230 65 100       277 if (is_module_name($name)) {
2231 62         212 $c->add_conditional($name => 0);
2232 62         2203 return;
2233             }
2234             }
2235              
2236             sub _no {
2237 32     32   73 my ($c, $rstr, $tokens) = @_;
2238 32         47 _debug("NO TOKENS: ".(Data::Dump::dump($tokens))) if DEBUG;
2239 32         60 shift @$tokens; # discard 'no' itself
2240              
2241             # TODO: see if the token is WORD or not?
2242 32 50       117 my $name_token = shift @$tokens or return;
2243 32         64 my $name = $name_token->[0];
2244 32 50 33     206 return if !defined $name or ref $name or $name eq '';
      33        
2245              
2246 32         80 my $c1 = substr($name, 0, 1);
2247 32 100       93 if ($c1 eq '5') {
2248 1         7 $c->add_no(perl => $name);
2249 1         143 return;
2250             }
2251 31 100       75 if ($c1 eq 'v') {
2252 1         3 my $c2 = substr($name, 1, 1);
2253 1 50       5 if ($c2 eq '5') {
2254 1         6 $c->add_no(perl => $name);
2255 1         187 return;
2256             }
2257 0 0       0 if ($c2 eq '6') {
2258 0         0 $c->{perl6} = 1;
2259 0         0 $c->{ended} = 1;
2260 0         0 return;
2261             }
2262             }
2263 30 50       77 if ($name eq 'utf8') {
2264 0         0 $c->{utf8} = 0;
2265             }
2266              
2267 30 50       128 if (is_module_name($name)) {
2268 30         59 my $maybe_version_token = $tokens->[0];
2269 30         52 my $maybe_version_token_desc = $maybe_version_token->[1];
2270 30 100 66     200 if ($maybe_version_token_desc and ($maybe_version_token_desc eq 'NUMBER' or $maybe_version_token_desc eq 'VERSION_STRING')) {
      66        
2271 3         14 $c->add_no($name => $maybe_version_token->[0]);
2272 3         320 shift @$tokens;
2273             } else {
2274 27         88 $c->add_no($name => 0);
2275             }
2276             }
2277              
2278 30 100       1121 if ($c->has_callback_for(no => $name)) {
2279 2         3 eval { $c->run_callback_for(no => $name, $tokens) };
  2         13  
2280 2 50       5 warn "Callback Error: $@" if $@;
2281 2         5 return;
2282             }
2283             }
2284              
2285             1;
2286              
2287             __END__