File Coverage

lib/Perl/PrereqScanner/NotQuiteLite.pm
Criterion Covered Total %
statement 1278 1462 87.4
branch 763 930 82.0
condition 284 397 71.5
subroutine 30 33 90.9
pod 3 3 100.0
total 2358 2825 83.4


line stmt bran cond sub pod time code
1             package Perl::PrereqScanner::NotQuiteLite;
2              
3 88     88   5097458 use strict;
  88         861  
  88         2188  
4 88     88   386 use warnings;
  88         151  
  88         1756  
5 88     88   355 use Carp;
  88         158  
  88         3855  
6 88     88   36193 use Perl::PrereqScanner::NotQuiteLite::Context;
  88         241  
  88         3399  
7 88     88   686 use Perl::PrereqScanner::NotQuiteLite::Util;
  88         152  
  88         13262  
8              
9             our $VERSION = '0.9915';
10              
11             our @BUNDLED_PARSERS = qw/
12             Aliased AnyMoose Autouse Catalyst ClassAccessor
13             ClassAutouse ClassLoad Core 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 88   50 88   657 use constant DEBUG => !!$ENV{PERL_PSNQL_DEBUG} || 0;
  88         188  
  88         6674  
23 88     88   584 use constant DEBUG_RE => DEBUG > 3 ? 1 : 0;
  88         188  
  88         8533  
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 88     88   558 no warnings 'redefine';
  88         183  
  88         1401620  
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   9 my $rstr = shift;
43 5         19 $@ = shift() . substr($$rstr, pos($$rstr), 100);
44 5         30 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 297     297   555 my $delim = shift;
110 297   66     1170 $ReStrInDelims{$delim} ||= do {
111 296 100       742 if ($delim eq '\\') {
112 2         10 qr/(?:[^\\]*(?:(?:\\\\)[^\\]*)*)/s;
113             } else {
114 294         545 $delim = quotemeta $delim;
115 294         5373 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   196 my $delim = shift;
127 96   66     448 $ReStrInDelimsWithEndDelim{$delim} ||= do {
128 33         138 my $re = _gen_re_str_in_delims($delim);
129 33         777 qr{$re\Q$delim\E};
130             };
131             }
132              
133             my %RdelSkip;
134             sub _gen_rdel_and_re_skip {
135 158     158   306 my $ldel = shift;
136 158   66     224 @{$RdelSkip{$ldel} ||= do {
  158         1075  
137 37         179 (my $rdel = $ldel) =~ tr/[({/;
138 37         678 my $re_skip = qr{[^\Q$ldel$rdel\E\\]+};
139 37         259 [$rdel, $re_skip];
140             }};
141             }
142              
143             my %RegexpShortcut;
144             sub _gen_re_regexp_shortcut {
145 198     198   474 my ($ldel, $rdel) = @_;
146 198   66     801 $RegexpShortcut{$ldel} ||= do {
147 28         79 $ldel = quotemeta $ldel;
148 28 100       83 $rdel = $rdel ? quotemeta $rdel : $ldel;
149 28         1188 qr{(?:[^\\\(\)\{\}\[\]<>$ldel$rdel]*(?:\\.[^\\\(\)\[\]\{\}<>$ldel$rdel]*)*)$rdel};
150             };
151             }
152              
153             ############################
154              
155             my %LOADED;
156              
157             sub new {
158 696     696 1 1841437 my ($class, %args) = @_;
159              
160 696         1435 my %mapping;
161 696         2389 my @parsers = $class->_get_parsers($args{parsers});
162 696         1604 for my $parser (@parsers) {
163 20742 100       42151 if (!exists $LOADED{$parser}) {
164 2433         124025 eval "require $parser; 1";
165 2433 50       10668 if (my $error = $@) {
166 0 0       0 $parser->can('register') or die "Parser Error: $error";
167             }
168 2433 50       32750 $LOADED{$parser} = $parser->can('register') ? $parser->register(%args) : undef;
169             }
170 20742 50       39935 my $parser_mapping = $LOADED{$parser} or next;
171 20742         29889 for my $type (qw/use no keyword method/) {
172 82968 100       137179 next unless exists $parser_mapping->{$type};
173 22824         27190 for my $name (keys %{$parser_mapping->{$type}}) {
  22824         56307  
174             $mapping{$type}{$name} = [
175             $parser,
176 120096 100 100     353921 $parser_mapping->{$type}{$name},
177             (($type eq 'use' or $type eq 'no') ? ($name) : ()),
178             ];
179             }
180             }
181 20742 100       91369 if ($parser->can('register_fqfn')) {
182 2076         6473 my $fqfn_mapping = $parser->register_fqfn;
183 2076         5782 for my $name (keys %$fqfn_mapping) {
184 6225         20248 my ($module) = $name =~ /^(.+)::/;
185             $mapping{keyword}{$name} = [
186             $parser,
187 6225         18482 $fqfn_mapping->{$name},
188             $module,
189             ];
190             }
191             }
192             }
193 696         1805 $args{_} = \%mapping;
194              
195 696         3662 bless \%args, $class;
196             }
197              
198             sub _get_parsers {
199 696     696   1597 my ($class, $list) = @_;
200 696         1298 my @parsers;
201             my %should_ignore;
202 696 50       1236 for my $parser (@{$list || [qw/:default/]}) {
  696         2556  
203 700 50       2632 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 691         1887 push @parsers, map {"$class\::Parser::$_"} @BUNDLED_PARSERS;
  20730         39140  
208             } elsif ($parser eq ':default') {
209 5         14 push @parsers, map {"$class\::Parser::$_"} @DEFAULT_PARSERS;
  10         38  
210             } elsif ($parser =~ s/^\+//) {
211 1         3 push @parsers, $parser;
212             } elsif ($parser =~ s/^\-//) {
213 1         5 $should_ignore{"$class\::Parser\::$parser"} = 1;
214             } elsif ($parser =~ /^$class\::Parser::/) {
215 1         4 push @parsers, $parser;
216             } else {
217 1         5 push @parsers, "$class\::Parser\::$parser";
218             }
219             }
220 696         1532 grep {!$should_ignore{$_}} @parsers;
  20743         31394  
221             }
222              
223             sub scan_file {
224 71     71 1 200 my ($self, $file) = @_;
225 71         123 _debug("START SCANNING $file") if DEBUG;
226 71 50       252 print STDERR " Scanning $file\n" if $self->{verbose};
227 71 50       3426 open my $fh, '<', $file or croak "Can't open $file: $!";
228 71         231 my $code = do { local $/; <$fh> };
  71         414  
  71         2569  
229 71         311 $self->{file} = $file;
230 71         274 $self->scan_string($code);
231             }
232              
233             sub scan_string {
234 696     696 1 3760 my ($self, $string) = @_;
235              
236 696 50       1750 $string = '' unless defined $string;
237              
238 696         4198 my $c = Perl::PrereqScanner::NotQuiteLite::Context->new(%$self);
239              
240 696 50       2505 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 696 50       3951 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 696         2087 $string =~ s/\A(\x00\x00\xfe\xff|\xff\xfe\x00\x00|\xfe\xff|\xff\xfe)//s;
252              
253             # normalize
254 696         1109 if ("\n" eq "\015") {
255             $string =~ s/(?:\015?\012)/\n/gs;
256             } elsif ("\n" eq "\012") {
257 696         1699 $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 696         11227 $string =~ s/[ \t]+/ /g;
264 696         12648 $string =~ s/(?: *\n)+/\n/gs;
265              
266             # FIXME
267 696         2231 $c->{stack} = [];
268 696         1543 $c->{errors} = [];
269             $c->{callback} = {
270 696         3202 use => \&_use,
271             require => \&_require,
272             no => \&_no,
273             };
274 696         1655 $c->{wants_doc} = 0;
275              
276 696         2290 pos($string) = 0;
277              
278             {
279 696         1442 local $@;
  705         1265  
280 705         1443 eval { $self->_scan($c, \$string, 0) };
  705         2535  
281 705 50       1644 push @{$c->{errors}}, "Scan Error: $@" if $@;
  0         0  
282 705 100       2085 if ($c->{redo}) {
283 9         70 delete $c->{redo};
284 9         14 delete $c->{ended};
285 9         13 @{$c->{stack}} = ();
  9         21  
286 9         19 redo;
287             }
288             }
289              
290 696 100 66     1280 if (@{$c->{stack}} and !$c->{quick}) {
  696         2137  
291 1         477 require Data::Dump;
292 1         4787 push @{$c->{errors}}, Data::Dump::dump($c->{stack});
  1         6  
293             }
294              
295 696         19105 $c->remove_inner_packages_from_requirements;
296 696         3088 $c->merge_perl;
297              
298 696         8914 $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 3088     3088   6425 my ($self, $c, $rstr, $parent_scope) = @_;
320              
321 3088 100       4429 if (@{$c->{stack}} > 90) {
  3088         7534  
322 1         12 _error("deep recursion found");
323 1         4 $c->{ended} = 1;
324             }
325              
326 3088         4172 _dump_stack($c, "BEGIN SCOPE") if DEBUG;
327              
328             # found __DATA|END__ somewhere?
329 3088 100       6035 return $c if $c->{ended};
330              
331 3087         4650 my $wants_doc = $c->{wants_doc};
332 3087         4119 my $line_top = 1;
333 3087         3981 my $waiting_for_a_block;
334              
335 3087         4151 my $current_scope = 0;
336 3087         5925 my ($token, $token_desc, $token_type) = ('', '', '');
337 3087         4756 my ($prev_token, $prev_token_type) = ('', '');
338 3087         12173 my ($stack, $unstack);
339 3087         0 my (@keywords, @tokens, @scope_tokens);
340 3087         0 my $caller_package;
341 3087         0 my $prepend;
342 3087         0 my ($pos, $c1);
343 3087         3977 my $prev_pos = 0;
344 3087         6628 while(defined($pos = pos($$rstr))) {
345 46315         58508 $token = undef;
346              
347             # cache first letter for better performance
348 46315         69229 $c1 = substr($$rstr, $pos, 1);
349              
350 46315 100       69985 if ($line_top) {
351 7467 100       12602 if ($c1 eq '=') {
352 10 50       413 if ($$rstr =~ m/\G($re_pod)/gcsx) {
353 10 50       31 ($token, $token_desc, $token_type) = ($1, 'POD', '') if $wants_doc;
354 10         20 next;
355             }
356             }
357             }
358 46305 100       70993 if ($c1 eq "\n") {
359 4113         8262 pos($$rstr)++;
360 4113         6420 $line_top = 1;
361 4113         10007 next;
362             }
363              
364 42192         50940 $line_top = 0;
365             # ignore whitespaces
366 42192 100       210442 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 14660         27114 pos($$rstr)++;
368 14660         23948 next;
369             } elsif ($c1 eq '_') {
370 57         197 my $c2 = substr($$rstr, $pos + 1, 1);
371 57 100 100     259 if ($c2 eq '_' and $$rstr =~ m/\G(__(?:DATA|END)__\b)(?!\s*=>)/gc) {
372 1 50       3 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         2 last;
378             }
379             }
380             } elsif ($c1 eq '#') {
381 257 50       4352 if ($$rstr =~ m{\G($re_comment)}gcs) {
382 257 50       645 ($token, $token_desc, $token_type) = ($1, 'COMMENT', '') if $wants_doc;
383 257         370 $line_top = 1;
384 257         454 next;
385             }
386             } elsif ($c1 eq ';') {
387 2587         5698 pos($$rstr) = $pos + 1;
388 2587         5830 ($token, $token_desc, $token_type) = ($c1, ';', ';');
389 2587         3738 $current_scope |= F_STATEMENT_END|F_EXPR_END;
390 2587         3482 next;
391             } elsif ($c1 eq '$') {
392 3668         6020 my $c2 = substr($$rstr, $pos + 1, 1);
393 3668 100 66     32364 if ($c2 eq '#') {
    100 100        
    100          
    100          
    100          
    100          
394 32 100       580 if (substr($$rstr, $pos + 2, 1) eq '{') {
    100          
    100          
395 2 50       10 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         6 pos($$rstr) = $pos + 3;
400 2         14 ($token, $token_desc, $token_type) = ('$#{', '$#{', 'EXPR');
401 2         7 $stack = [$token, $pos, 'VARIABLE'];
402 2         5 next;
403             }
404             } elsif ($$rstr =~ m{\G(\$\#(?:$re_namespace))}gc) {
405 14         52 ($token, $token_desc, $token_type) = ($1, '$#NAME', 'EXPR');
406 14         29 next;
407             } elsif ($prev_token_type eq 'ARROW') {
408 2         8 my $c3 = substr($$rstr, $pos + 2, 1);
409 2 50       7 if ($c3 eq '*') {
410 2         5 pos($$rstr) = $pos + 3;
411 2         6 ($token, $token_desc, $token_type) = ('$#*', 'VARIABLE', 'VARIABLE');
412 2         8 $c->add_perl('5.020', '->$#*');
413 2         4 next;
414             }
415             } else {
416 14         90 pos($$rstr) = $pos + 2;
417 14         43 ($token, $token_desc, $token_type) = ('$#', 'SPECIAL_VARIABLE', 'EXPR');
418 14         27 next;
419             }
420             } elsif ($c2 eq '$') {
421 44 100       512 if ($$rstr =~ m{\G(\$(?:\$)+(?:$re_namespace))}gc) {
422 42         127 ($token, $token_desc, $token_type) = ($1, '$$NAME', 'VARIABLE');
423 42         83 next;
424             } else {
425 2         7 pos($$rstr) = $pos + 2;
426 2         7 ($token, $token_desc, $token_type) = ('$$', 'SPECIAL_VARIABLE', 'EXPR');
427 2         5 next;
428             }
429             } elsif ($c2 eq '{') {
430 10 100       58 if ($$rstr =~ m{\G(\$\{[\w\s]+\})}gc) {
    50          
431 2         7 ($token, $token_desc, $token_type) = ($1, '${NAME}', 'VARIABLE');
432 2 50 33     8 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         23 pos($$rstr) = $pos + 2;
446 8         25 ($token, $token_desc, $token_type) = ('${', '${', 'VARIABLE');
447 8         19 $stack = [$token, $pos, 'VARIABLE'];
448             }
449 10 100       26 if ($parent_scope & F_EXPECTS_BRACKET) {
450 3         6 $current_scope |= F_SCOPE_END;
451             }
452 10         19 next;
453             } elsif ($c2 eq '*' and $prev_token_type eq 'ARROW') {
454 2         6 pos($$rstr) = $pos + 2;
455 2         5 ($token, $token_desc, $token_type) = ('$*', '$*', 'VARIABLE');
456 2         13 $c->add_perl('5.020', '->$*');
457 2         3 next;
458             } elsif ($c2 eq '+' or $c2 eq '-') {
459 2         3 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 3576         9814 ($token, $token_desc, $token_type) = ($1, '$NAME', 'VARIABLE');
465 3576         5852 next;
466             } else {
467 2         7 pos($$rstr) = $pos + 1;
468 2         6 ($token, $token_desc, $token_type) = ($c1, $c1, 'VARIABLE');
469 2         4 next;
470             }
471             } elsif ($c1 eq '@') {
472 317         678 my $c2 = substr($$rstr, $pos + 1, 1);
473 317 100 100     2996 if ($c2 eq '_' and $$rstr =~ m{\G\@_\b}gc) {
    100 100        
    100          
    100          
    100          
    100          
    50          
474 118         323 ($token, $token_desc, $token_type) = ('@_', 'SPECIAL_VARIABLE', 'VARIABLE');
475 118         190 next;
476             } elsif ($c2 eq '{') {
477 37 50       236 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     6 if ($token eq '@{^CAPTURE}' or $token eq '@{^CAPTURE_ALL}') {
485 2         6 $c->add_perl('5.026', '@{^CAPTURE}');
486             }
487             } else {
488 35         98 pos($$rstr) = $pos + 2;
489 35         95 ($token, $token_desc, $token_type) = ('@{', '@{', 'VARIABLE');
490 35         95 $stack = [$token, $pos, 'VARIABLE'];
491             }
492 37 100       100 if ($prev_token_type eq 'ARROW') {
493 5         12 $c->add_perl('5.020', '->@{}');
494             }
495 37 50       111 if ($parent_scope & F_EXPECTS_BRACKET) {
496 0         0 $current_scope |= F_SCOPE_END;
497             }
498 37         64 next;
499             } elsif ($c2 eq '$') {
500 37 100       481 if ($$rstr =~ m{\G(\@\$(?:$re_namespace))}gc) {
501 35         106 ($token, $token_desc, $token_type) = ($1, '@$NAME', 'VARIABLE');
502 35         65 next;
503             } else {
504 2         8 pos($$rstr) = $pos + 2;
505 2         6 ($token, $token_desc, $token_type) = ('@$', '@$', 'VARIABLE');
506 2         4 next;
507             }
508             } elsif ($prev_token_type eq 'ARROW') {
509             # postderef
510 11 100       19 if ($c2 eq '*') {
511 5         9 pos($$rstr) = $pos + 2;
512 5         12 ($token, $token_desc, $token_type) = ('@*', '@*', 'VARIABLE');
513 5         13 $c->add_perl('5.020', '->@*');
514 5         6 next;
515             } else {
516 6         12 pos($$rstr) = $pos + 1;
517 6         12 ($token, $token_desc, $token_type) = ('@', '@', 'VARIABLE');
518 6         17 $c->add_perl('5.020', '->@');
519 6         10 next;
520             }
521             } elsif ($c2 eq '[') {
522 1         4 pos($$rstr) = $pos + 2;
523 1         5 ($token, $token_desc, $token_type) = ('@[', 'SPECIAL_VARIABLE', 'VARIABLE');
524 1         2 next;
525             } elsif ($c2 eq '+' or $c2 eq '-') {
526 2         5 pos($$rstr) = $pos + 2;
527 2         6 ($token, $token_desc, $token_type) = ('@'.$c2, 'SPECIAL_VARIABLE', 'VARIABLE');
528 2         7 $c->add_perl('5.010', '@'.$c2);
529 2         5 next;
530             } elsif ($$rstr =~ m{\G(\@(?:$re_namespace))}gc) {
531 111         371 ($token, $token_desc, $token_type) = ($1, '@NAME', 'VARIABLE');
532 111         211 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         272 my $c2 = substr($$rstr, $pos + 1, 1);
540 117 100 66     1885 if ($c2 eq '{') {
    100 66        
    100          
    100          
    100          
    100          
    50          
541 42 50       264 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         9 ($token, $token_desc, $token_type) = ($1, '%{^NAME}', 'VARIABLE');
545 2 50 66     10 if ($token eq '%{^CAPTURE}' or $token eq '%{^CAPTURE_ALL}') {
546 2         6 $c->add_perl('5.026', '%{^CAPTURE}');
547             }
548             } else {
549 40         130 pos($$rstr) = $pos + 2;
550 40         119 ($token, $token_desc, $token_type) = ('%{', '%{', 'VARIABLE');
551 40         111 $stack = [$token, $pos, 'VARIABLE'];
552             }
553 42 100       103 if ($prev_token_type eq 'ARROW') {
554 4         9 $c->add_perl('5.020', '->%{');
555             }
556 42 50       104 if ($parent_scope & F_EXPECTS_BRACKET) {
557 0         0 $current_scope |= F_SCOPE_END;
558             }
559 42         60 next;
560             } elsif ($c2 eq '=') {
561 1         6 pos($$rstr) = $pos + 2;
562 1         4 ($token, $token_desc, $token_type) = ('%=', '%=', 'OP');
563 1         4 next;
564             } elsif ($$rstr =~ m{\G(\%\$(?:$re_namespace))}gc) {
565 5         26 ($token, $token_desc, $token_type) = ($1, '%$NAME', 'VARIABLE');
566 5         11 next;
567             } elsif ($$rstr =~ m{\G(\%(?:$re_namespace))}gc) {
568 57         193 ($token, $token_desc, $token_type) = ($1, '%NAME', 'VARIABLE');
569 57         117 next;
570             } elsif ($prev_token_type eq 'VARIABLE' or $prev_token_type eq 'EXPR') {
571 4         15 pos($$rstr) = $pos + 1;
572 4         12 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
573 4         7 next;
574             } elsif ($prev_token_type eq 'ARROW') {
575 6 100       15 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         5 next;
580             } else {
581 4         10 pos($$rstr) = $pos + 1;
582 4         9 ($token, $token_desc, $token_type) = ('%', '%', 'VARIABLE');
583 4         10 $c->add_perl('5.020', '->%');
584 4         8 next;
585             }
586             } elsif ($c2 eq '+' or $c2 eq '-') {
587 2         6 pos($$rstr) = $pos + 2;
588 2         7 ($token, $token_desc, $token_type) = ('%'.$c2, 'SPECIAL_VARIABLE', 'VARIABLE');
589 2         8 $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         202 my $c2 = substr($$rstr, $pos + 1, 1);
598 89 100       857 if ($c2 eq '{') {
    100          
    100          
    100          
599 15 100       60 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         6 $c->add_perl('5.020', '->*{}');
603 2         4 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         45 pos($$rstr) = $pos + 2;
612 13         34 ($token, $token_desc, $token_type) = ('*{', '*{', 'VARIABLE');
613 13         34 $stack = [$token, $pos, 'VARIABLE'];
614             }
615 13 50       32 if ($parent_scope & F_EXPECTS_BRACKET) {
616 0         0 $current_scope |= F_SCOPE_END;
617             }
618 13         21 next;
619             } elsif ($c2 eq '*') {
620 3 50       18 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         6 pos($$rstr) = $pos + 2;
626 2         5 ($token, $token_desc, $token_type) = ('**', '**', 'VARIABLE');
627 2         6 $c->add_perl('5.020', '->**');
628 2         3 next;
629             } else {
630 1         4 pos($$rstr) = $pos + 2;
631 1         4 ($token, $token_desc, $token_type) = ('**', '**', 'OP');
632 1         2 next;
633             }
634             } elsif ($c2 eq '=') {
635 2         8 pos($$rstr) = $pos + 2;
636 2         7 ($token, $token_desc, $token_type) = ('*=', '*=', 'OP');
637 2         5 next;
638             } elsif ($$rstr =~ m{\G(\*(?:$re_namespace))}gc) {
639 29         86 ($token, $token_desc, $token_type) = ($1, '*NAME', 'VARIABLE');
640 29         72 next;
641             } else {
642 40         103 pos($$rstr) = $pos + 1;
643 40         95 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
644 40         140 next;
645             }
646             } elsif ($c1 eq '&') {
647 129         282 my $c2 = substr($$rstr, $pos + 1, 1);
648 129 100       1209 if ($c2 eq '&') {
    50          
    100          
    100          
    100          
    100          
    100          
649 58         125 pos($$rstr) = $pos + 2;
650 58         152 ($token, $token_desc, $token_type) = ('&&', '&&', 'OP');
651 58         91 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       48 if ($$rstr =~ m{\G(\&\{[\w\s]+\})}gc) {
658 0         0 ($token, $token_desc, $token_type) = ($1, '&{NAME}', 'EXPR');
659             } else {
660 8         21 pos($$rstr) = $pos + 2;
661 8         20 ($token, $token_desc, $token_type) = ('&{', '&{', 'EXPR');
662 8         16 $stack = [$token, $pos, 'FUNC'];
663             }
664 8 50       75 if ($parent_scope & F_EXPECTS_BRACKET) {
665 0         0 $current_scope |= F_SCOPE_END;
666             }
667 8         15 next;
668             } elsif ($c2 eq '.') {
669 2 100       23 if (substr($$rstr, $pos + 2, 1) eq '=') {
670 1         3 pos($$rstr) = $pos + 3;
671 1         4 ($token, $token_desc, $token_type) = ('&.=', '&.=', 'OP');
672             } else {
673 1         5 pos($$rstr) = $pos + 2;
674 1         3 ($token, $token_desc, $token_type) = ('&.', '&.', 'OP');
675             }
676 2         7 $c->add_perl('5.022', '&.');
677 2         4 next;
678             } elsif ($$rstr =~ m{\G(\&(?:$re_namespace))}gc) {
679 48         136 ($token, $token_desc, $token_type) = ($1, '&NAME', 'EXPR');
680 48         86 next;
681             } elsif ($$rstr =~ m{\G(\&\$(?:$re_namespace))}gc) {
682 3         10 ($token, $token_desc, $token_type) = ($1, '&$NAME', 'EXPR');
683 3         6 next;
684             } elsif ($prev_token_type eq 'ARROW') {
685 2 50       13 if ($c2 eq '*') {
686 2         7 pos($$rstr) = $pos + 2;
687 2         6 ($token, $token_desc, $token_type) = ('&*', '&*', 'VARIABLE');
688 2         9 $c->add_perl('5.020', '->&*');
689 2         5 next;
690             }
691             } else {
692 8         26 pos($$rstr) = $pos + 1;
693 8         22 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
694 8         15 next;
695             }
696             } elsif ($c1 eq '\\') {
697 70         161 my $c2 = substr($$rstr, $pos + 1, 1);
698 70 50       165 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         152 pos($$rstr) = $pos + 1;
712 70         168 ($token, $token_desc, $token_type) = ($c1, $c1, '');
713 70         100 next;
714             }
715             } elsif ($c1 eq '-') {
716 1267         2357 my $c2 = substr($$rstr, $pos + 1, 1);
717 1267 100       2765 if ($c2 eq '>') {
    100          
    100          
    100          
718 1103         2256 pos($$rstr) = $pos + 2;
719 1103         2528 ($token, $token_desc, $token_type) = ('->', 'ARROW', 'ARROW');
720 1103 100 100     3228 if ($prev_token_type eq 'WORD' or $prev_token_type eq 'KEYWORD') {
721 51         99 $caller_package = $prev_token;
722 51         89 $current_scope |= F_KEEP_TOKENS;
723             }
724 1103         1581 next;
725             } elsif ($c2 eq '-') {
726 4         12 pos($$rstr) = $pos + 2;
727 4         16 ($token, $token_desc, $token_type) = ('--', '--', $prev_token_type);
728 4         9 next;
729             } elsif ($c2 eq '=') {
730 5         17 pos($$rstr) = $pos + 2;
731 5         17 ($token, $token_desc, $token_type) = ('-=', '-=', 'OP');
732 5         8 next;
733             } elsif ($$rstr =~ m{\G(\-[ABCMORSTWXbcdefgkloprstuwxz]\b)}gc) {
734 4         17 ($token, $token_desc, $token_type) = ($1, 'FILE_TEST', 'EXPR');
735 4         9 next;
736             } else {
737 151         354 pos($$rstr) = $pos + 1;
738 151         385 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
739 151         255 next;
740             }
741             } elsif ($c1 eq q{"}) {
742 436 100       4086 if ($$rstr =~ m{\G(?:\"($re_str_in_double_quotes)\")}gcs) {
743 435         1830 ($token, $token_desc, $token_type) = ([$1, q{"}], 'STRING', 'STRING');
744 435         812 next;
745             }
746             } elsif ($c1 eq q{'}) {
747 859 50       7500 if ($$rstr =~ m{\G(?:\'($re_str_in_single_quotes)\')}gcs) {
748 859         3401 ($token, $token_desc, $token_type) = ([$1, q{'}], 'STRING', 'STRING');
749 859         1546 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     815 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       307 if (my $regexp = $self->_match_regexp0($c, $rstr, $pos, 'm')) {
759 96         238 ($token, $token_desc, $token_type) = ($regexp, 'REGEXP', 'EXPR');
760 96         172 next;
761             } else {
762             # the above may fail
763 1         2 _debug("REGEXP ERROR: $@") if DEBUG;
764 1         3 pos($$rstr) = $pos;
765             }
766             }
767 48 50 33     356 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       7 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         3 pos($$rstr) = $pos;
776             }
777             }
778 48         116 my $c2 = substr($$rstr, $pos + 1, 1);
779 48 100       130 if ($c2 eq '/') {
780 9 100       27 if (substr($$rstr, $pos + 2, 1) eq '=') {
781 2         8 pos($$rstr) = $pos + 3;
782 2         5 ($token, $token_desc, $token_type) = ('//=', '//=', 'OP');
783 2         9 $c->add_perl('5.010', '//=');
784 2         3 next;
785             } else {
786 7         12 pos($$rstr) = $pos + 2;
787 7         18 ($token, $token_desc, $token_type) = ('//', '//', 'OP');
788 7         26 $c->add_perl('5.010', '//');
789 7         11 next;
790             }
791             }
792 39 100       83 if ($c2 eq '=') { # this may be a part of /=.../
793 1         5 pos($$rstr) = $pos + 2;
794 1         4 ($token, $token_desc, $token_type) = ('/=', '/=', 'OP');
795 1         2 next;
796             } else {
797 38         86 pos($$rstr) = $pos + 1;
798 38         108 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
799 38         76 next;
800             }
801             } elsif ($c1 eq '{') {
802 1785 100       13107 if ($$rstr =~ m{$g_re_hash_shortcut}gc) {
803 879         2269 ($token, $token_desc) = ($1, '{EXPR}');
804 879 100       1836 if ($current_scope & F_EVAL) {
805 1         2 $current_scope &= MASK_EVAL;
806 1 50       8 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
807             }
808 879 100       1645 if ($parent_scope & F_EXPECTS_BRACKET) {
809 8         11 $current_scope |= F_SCOPE_END;
810 8         14 next;
811             }
812 871 100 100     2518 if ($prev_token_type eq 'ARROW' or $prev_token_type eq 'VARIABLE') {
    100 100        
    100          
813 755         1063 $token_type = 'VARIABLE';
814 755         1046 next;
815             } elsif ($waiting_for_a_block) {
816 82         129 $waiting_for_a_block = 0;
817 82 100 100     333 if (@keywords and $c->token_expects_block($keywords[0])) {
818 70         114 my $first_token = $keywords[0];
819 70         126 $current_scope |= F_EXPR_END;
820 70 100 100     169 if ($c->token_defines_sub($first_token) and $c->has_callback_for(sub => $first_token)) {
821 3         10 $c->run_callback_for(sub => $first_token, \@tokens);
822 3         7 $current_scope &= MASK_KEEP_TOKENS;
823 3         7 @tokens = ();
824             }
825             }
826 82         245 next;
827             } elsif ($prev_token_type eq 'KEYWORD' and $c->token_expects_fh_or_block_list($prev_token)) {
828 15         21 $token_type = '';
829 15         22 next;
830             } else {
831 19         36 $token_type = 'EXPR';
832 19         36 next;
833             }
834             }
835 906         2427 pos($$rstr) = $pos + 1;
836 906         2325 ($token, $token_desc) = ($c1, $c1);
837 906         1331 my $stack_owner;
838 906 100       1894 if (@keywords) {
839 713         1938 for(my $i = @keywords; $i > 0; $i--) {
840 745         1456 my $keyword = $keywords[$i - 1];
841 745 100       1861 if ($c->token_expects_block($keyword)) {
842 672         1101 $stack_owner = $keyword;
843 672 100 100     1619 if (@tokens and $c->token_defines_sub($keyword) and $c->has_callback_for(sub => $keyword)) {
      100        
844 40         169 $c->run_callback_for(sub => $keyword, \@tokens);
845 40         666 $current_scope &= MASK_KEEP_TOKENS;
846 40         104 @tokens = ();
847             }
848 672         1167 last;
849             }
850             }
851             }
852 906   100     2957 $stack = [$token, $pos, $stack_owner || ''];
853 906 100       2087 if ($parent_scope & F_EXPECTS_BRACKET) {
854 62         87 $current_scope |= F_SCOPE_END|F_STATEMENT_END|F_EXPR_END;
855 62         96 next;
856             }
857 844 100 100     3335 if ($prev_token_type eq 'ARROW' or $prev_token_type eq 'VARIABLE') {
    100          
858 35         75 $token_type = 'VARIABLE';
859             } elsif ($waiting_for_a_block) {
860 676         1026 $waiting_for_a_block = 0;
861             } else {
862 133 100       392 $token_type = (($current_scope | $parent_scope) & F_KEEP_TOKENS) ? 'EXPR' : '';
863             }
864 844         1311 next;
865             } elsif ($c1 eq '[') {
866 395 100       3215 if ($$rstr =~ m{\G(\[(?:$re_nonblock_chars)\])}gc) {
867 208         567 ($token, $token_desc, $token_type) = ($1, '[EXPR]', 'VARIABLE');
868 208         350 next;
869             } else {
870 187         539 pos($$rstr) = $pos + 1;
871 187         533 ($token, $token_desc, $token_type) = ($c1, $c1, 'VARIABLE');
872 187         433 $stack = [$token, $pos, 'VARIABLE'];
873 187         340 next;
874             }
875             } elsif ($c1 eq '(') {
876 1486         3832 my $prototype_re = $c->prototype_re;
877 1486 100 100     11697 if ($waiting_for_a_block and @keywords and $c->token_defines_sub($keywords[-1]) and $$rstr =~ m{$prototype_re}gc) {
    100 100        
      100        
878 101         253 my $proto = $1;
879 101 100       396 if ($proto =~ /^\([\\\$\@\%\&\[\]\*;\+]*\)$/) {
880 56         125 ($token, $token_desc, $token_type) = ($proto, '(PROTOTYPE)', '');
881             } else {
882 45         102 ($token, $token_desc, $token_type) = ($proto, '(SIGNATURES)', '');
883 45         129 $c->add_perl('5.020', 'signatures');
884             }
885 101         169 next;
886             } elsif ($$rstr =~ m{\G\(((?:$re_nonblock_chars)(?
887 295         1662 ($token, $token_desc, $token_type) = ([[[$1, 'EXPR']]], '()', 'EXPR');
888 295 100 100     1554 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       171 if ($prev_token eq 'eval') {
890 1         4 $current_scope &= MASK_EVAL;
891 1 50       4 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
892             }
893 54         97 pop @keywords;
894             }
895 295         596 next;
896             } else {
897 1090         3047 pos($$rstr) = $pos + 1;
898 1090         2596 ($token, $token_desc, $token_type) = ($c1, $c1, 'EXPR');
899 1090         1551 my $stack_owner;
900 1090 100       2251 if (@keywords) {
901 609         1579 for (my $i = @keywords; $i > 0; $i--) {
902 661         1257 my $keyword = $keywords[$i - 1];
903 661 100       1489 if ($c->token_expects_block($keyword)) {
904 215         388 $stack_owner = $keyword;
905 215         492 last;
906             }
907             }
908             }
909 1090   100     4068 $stack = [$token, $pos, $stack_owner || ''];
910 1090         2192 next;
911             }
912             } elsif ($c1 eq '}') {
913 1009         2261 pos($$rstr) = $pos + 1;
914 1009         2262 ($token, $token_desc, $token_type) = ($c1, $c1, '');
915 1009         1453 $unstack = $token;
916 1009         1601 $current_scope |= F_STATEMENT_END|F_EXPR_END;
917 1009         1488 next;
918             } elsif ($c1 eq ']') {
919 96         244 pos($$rstr) = $pos + 1;
920 96         234 ($token, $token_desc, $token_type) = ($c1, $c1, '');
921 96         182 $unstack = $token;
922 96         148 next;
923             } elsif ($c1 eq ')') {
924 1090         2525 pos($$rstr) = $pos + 1;
925 1090         2523 ($token, $token_desc, $token_type) = ($c1, $c1, '');
926 1090         1536 $unstack = $token;
927 1090         1511 next;
928             } elsif ($c1 eq '<') {
929 93         274 my $c2 = substr($$rstr, $pos + 1, 1);
930 93 100       692 if ($c2 eq '<'){
    100          
    100          
    100          
931 19 100       164 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         5 $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       63 if (my $heredoc = $self->_match_heredoc($c, $rstr)) {
952 14         38 ($token, $token_desc, $token_type) = ($heredoc, 'HEREDOC', 'EXPR');
953 14         28 next;
954             } else {
955             # the above may fail
956 2         4 pos($$rstr) = $pos;
957             }
958             }
959 4 50       20 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         8 pos($$rstr) = $pos + 2;
965 4         9 ($token, $token_desc, $token_type) = ('<<', '<<', 'OP');
966 4         5 next;
967             }
968             } elsif ($c2 eq '=') {
969 10 100       48 if (substr($$rstr, $pos + 2, 1) eq '>') {
970 1         5 pos($$rstr) = $pos + 3;
971 1         6 ($token, $token_desc, $token_type) = ('<=>', '<=>', 'OP');
972 1         2 next;
973             } else {
974 9         23 pos($$rstr) = $pos + 2;
975 9         24 ($token, $token_desc, $token_type) = ('<=', '<=', 'OP');
976 9         21 next;
977             }
978             } elsif ($c2 eq '>') {
979 1         3 pos($$rstr) = $pos + 2;
980 1         5 ($token, $token_desc, $token_type) = ('<>', '<>', 'OP');
981 1         1 next;
982             } elsif ($$rstr =~ m{\G(<(?:
983             \\. |
984             \w+ |
985             [./-] |
986             \[[^\]]*\] |
987             \{[^\}]*\} |
988             \* |
989             \? |
990             \~ |
991             \$ |
992             )*(?)}gcx) {
993 12         43 ($token, $token_desc, $token_type) = ($1, '', 'EXPR');
994 12         30 next;
995             } else {
996 51         133 pos($$rstr) = $pos + 1;
997 51         127 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
998 51         78 next;
999             }
1000             } elsif ($c1 eq ':') {
1001 227         527 my $c2 = substr($$rstr, $pos + 1, 1);
1002 227 100       508 if ($c2 eq ':') {
1003 21         53 pos($$rstr) = $pos + 2;
1004 21         54 ($token, $token_desc, $token_type) = ('::', '::', '');
1005 21         36 next;
1006             }
1007 206 100 100     794 if ($waiting_for_a_block and @keywords and $c->token_defines_sub($keywords[-1])) {
      100        
1008 44         159 while($$rstr =~ m{\G\s*(:?\s*[\w]+)}gcs) {
1009 75         114 my $startpos = pos($$rstr);
1010 75 100       187 if (substr($$rstr, $startpos, 1) eq '(') {
1011 44         82 my @nest = '(';
1012 44         87 pos($$rstr) = $startpos + 1;
1013 44         76 my ($p, $c1);
1014 44         83 while(defined($p = pos($$rstr))) {
1015 103         145 $c1 = substr($$rstr, $p, 1);
1016 103 50       170 if ($c1 eq '\\') {
1017 0         0 pos($$rstr) = $p + 2;
1018 0         0 next;
1019             }
1020 103 100       162 if ($c1 eq ')') {
1021 50         63 pop @nest;
1022 50         103 pos($$rstr) = $p + 1;
1023 50 100       188 last unless @nest;
1024             }
1025 59 100       94 if ($c1 eq '(') {
1026 6         12 push @nest, $c1;
1027 6         12 pos($$rstr) = $p + 1;
1028 6         10 next;
1029             }
1030 53 100       159 $$rstr =~ m{\G([^\\()]+)}gc and next;
1031             }
1032             }
1033             }
1034 44         99 $token = substr($$rstr, $pos, pos($$rstr) - $pos);
1035 44         76 ($token_desc, $token_type) = ('ATTRIBUTE', '');
1036 44 100       87 if ($token =~ /^:prototype\(/) {
1037 2         6 $c->add_perl('5.020', ':prototype');
1038             }
1039 44         65 next;
1040             } else {
1041 162         378 pos($$rstr) = $pos + 1;
1042 162         435 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1043 162         253 next;
1044             }
1045             } elsif ($c1 eq '=') {
1046 1706         3440 my $c2 = substr($$rstr, $pos + 1, 1);
1047 1706 100       4115 if ($c2 eq '>') {
    100          
    100          
1048 600         1201 pos($$rstr) = $pos + 2;
1049 600         1353 ($token, $token_desc, $token_type) = ('=>', 'COMMA', 'OP');
1050 600 100 100     1752 if (@keywords and $prev_token_type eq 'KEYWORD' and $keywords[-1] eq $prev_token) {
      66        
1051 19         36 pop @keywords;
1052 19 100 100     94 if (!@keywords and ($current_scope & F_KEEP_TOKENS)) {
1053 1         2 $current_scope &= MASK_KEEP_TOKENS;
1054 1         2 @tokens = ();
1055             }
1056             }
1057 600         1014 next;
1058             } elsif ($c2 eq '=') {
1059 74         162 pos($$rstr) = $pos + 2;
1060 74         155 ($token, $token_desc, $token_type) = ('==', '==', 'OP');
1061 74         107 next;
1062             } elsif ($c2 eq '~') {
1063 101         253 pos($$rstr) = $pos + 2;
1064 101         224 ($token, $token_desc, $token_type) = ('=~', '=~', 'OP');
1065 101         266 next;
1066             } else {
1067 931         1884 pos($$rstr) = $pos + 1;
1068 931         1997 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1069 931         1362 next;
1070             }
1071             } elsif ($c1 eq '>') {
1072 54         177 my $c2 = substr($$rstr, $pos + 1, 1);
1073 54 50       181 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         10 next;
1087             } else {
1088 50         106 pos($$rstr) = $pos + 1;
1089 50         122 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1090 50         92 next;
1091             }
1092             } elsif ($c1 eq '+') {
1093 134         367 my $c2 = substr($$rstr, $pos + 1, 1);
1094 134 100       390 if ($c2 eq '+') {
    100          
1095 19 50       69 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         53 pos($$rstr) = $pos + 2;
1101 19         58 ($token, $token_desc, $token_type) = ('++', '++', $prev_token_type);
1102 19         31 next;
1103             }
1104             } elsif ($c2 eq '=') {
1105 40         82 pos($$rstr) = $pos + 2;
1106 40         85 ($token, $token_desc, $token_type) = ('+=', '+=', 'OP');
1107 40         71 next;
1108             } else {
1109 75         186 pos($$rstr) = $pos + 1;
1110 75         178 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1111 75         118 next;
1112             }
1113             } elsif ($c1 eq '|') {
1114 93         249 my $c2 = substr($$rstr, $pos + 1, 1);
1115 93 100       255 if ($c2 eq '|') {
    100          
    100          
1116 85 100       253 if (substr($$rstr, $pos + 2, 1) eq '=') {
1117 17         38 pos($$rstr) = $pos + 3;
1118 17         69 ($token, $token_desc, $token_type) = ('||=', '||=', 'OP');
1119 17         31 next;
1120             } else {
1121 68         156 pos($$rstr) = $pos + 2;
1122 68         175 ($token, $token_desc, $token_type) = ('||', '||', 'OP');
1123 68         119 next;
1124             }
1125             } elsif ($c2 eq '=') {
1126 1         3 pos($$rstr) = $pos + 2;
1127 1         3 ($token, $token_desc, $token_type) = ('|=', '|=', 'OP');
1128 1         2 next;
1129             } elsif ($c2 eq '.') {
1130 2 100       5 if (substr($$rstr, $pos + 2, 1) eq '=') {
1131 1         3 pos($$rstr) = $pos + 3;
1132 1         4 ($token, $token_desc, $token_type) = ('|.=', '|.=', 'OP');
1133             } else {
1134 1         3 pos($$rstr) = $pos + 2;
1135 1         3 ($token, $token_desc, $token_type) = ('|.', '|.', 'OP');
1136             }
1137 2         7 $c->add_perl('5.022', '|.');
1138 2         4 next;
1139             } else {
1140 5         12 pos($$rstr) = $pos + 1;
1141 5         22 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1142 5         16 next;
1143             }
1144             } elsif ($c1 eq '^') {
1145 4         13 my $c2 = substr($$rstr, $pos + 1, 1);
1146 4 50       15 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       6 if (substr($$rstr, $pos + 2, 1) eq '=') {
1152 1         3 pos($$rstr) = $pos + 3;
1153 1         4 ($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         6 $c->add_perl('5.022', '^.');
1159 2         4 next;
1160             } else {
1161 2         5 pos($$rstr) = $pos + 1;
1162 2         6 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1163 2         4 next;
1164             }
1165             } elsif ($c1 eq '!') {
1166 51         134 my $c2 = substr($$rstr, $pos + 1, 1);
1167 51 100       117 if ($c2 eq '~') {
1168 5         15 pos($$rstr) = $pos + 2;
1169 5         18 ($token, $token_desc, $token_type) = ('!~', '!~', 'OP');
1170 5         8 next;
1171             } else {
1172 46         106 pos($$rstr) = $pos + 1;
1173 46         130 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1174 46         73 next;
1175             }
1176             } elsif ($c1 eq '~') {
1177 2         5 my $c2 = substr($$rstr, $pos + 1, 1);
1178 2 100       6 if ($c2 eq '~') {
    50          
1179 1         4 pos($$rstr) = $pos + 2;
1180 1         3 ($token, $token_desc, $token_type) = ('~~', '~~', 'OP');
1181 1         3 $c->add_perl('5.010', '~~');
1182 1         2 next;
1183             } elsif ($c2 eq '.') {
1184 1         3 pos($$rstr) = $pos + 2;
1185 1         3 ($token, $token_desc, $token_type) = ('~.', '~.', 'OP');
1186 1         4 $c->add_perl('5.022', '~.');
1187 1         2 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 1389         3402 pos($$rstr) = $pos + 1;
1195 1389         3227 ($token, $token_desc, $token_type) = ($c1, 'COMMA', 'OP');
1196 1389         2009 next;
1197             } elsif ($c1 eq '?') {
1198 131         311 pos($$rstr) = $pos + 1;
1199 131         320 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1200 131         189 next;
1201             } elsif ($c1 eq '.') {
1202 195         456 my $c2 = substr($$rstr, $pos + 1, 1);
1203 195 100       508 if ($c2 eq '.') {
    100          
1204 20 100       94 if (substr($$rstr, $pos + 2, 1) eq '.') {
1205 15         38 pos($$rstr) = $pos + 3;
1206 15         39 ($token, $token_desc, $token_type) = ('...', '...', 'OP');
1207 15         58 $c->add_perl('5.012', '...');
1208 15         33 next;
1209             } else {
1210 5         14 pos($$rstr) = $pos + 2;
1211 5         18 ($token, $token_desc, $token_type) = ('..', '..', 'OP');
1212 5         9 next;
1213             }
1214             } elsif ($c2 eq '=') {
1215 26         66 pos($$rstr) = $pos + 2;
1216 26         74 ($token, $token_desc, $token_type) = ('.=', '.=', 'OP');
1217 26         45 next;
1218             } else {
1219 149         325 pos($$rstr) = $pos + 1;
1220 149         363 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1221 149         277 next;
1222             }
1223             } elsif ($c1 eq '0') {
1224 219         507 my $c2 = substr($$rstr, $pos + 1, 1);
1225 219 100       620 if ($c2 eq 'x') {
    50          
1226 4 50       21 if ($$rstr =~ m{\G(0x[0-9A-Fa-f_]+)}gc) {
1227 4         13 ($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 7648 100       23859 if ($$rstr =~ m{\G((?:0|[1-9][0-9_]*)(?:\.[0-9][0-9_]*)?)}gc) {
1239 650         1445 my $number = $1;
1240 650         1032 my $p = pos($$rstr);
1241 650         1283 my $n1 = substr($$rstr, $p, 1);
1242 650 100 33     2624 if ($n1 eq '.') {
    50          
1243 9 50       63 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         15 $number .= '.';
1249 7         15 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 650         1506 ($token, $token_desc, $token_type) = ($number, 'NUMBER', 'EXPR');
1257 650 100       1309 if ($prepend) {
1258 2         6 $token = "$prepend$token";
1259 2 50 33     15 pop @tokens if @tokens and $tokens[-1][0] eq $prepend;
1260 2 50 33     11 pop @scope_tokens if @scope_tokens and $scope_tokens[-1][0] eq $prepend;
1261             }
1262 650         1086 next;
1263             }
1264              
1265 6998 100 100     21130 if ($prev_token_type ne 'ARROW' and ($prev_token_type ne 'KEYWORD' or !$c->token_expects_word($prev_token))) {
      100        
1266 5421 100 100     15637 if ($prev_token_type eq 'EXPR' or $prev_token_type eq 'VARIABLE') {
1267 330 100       758 if ($c1 eq 'x') {
1268 5 100       26 if ($$rstr =~ m{\G(x\b(?!\s*=>))}gc){
1269 3         11 ($token, $token_desc, $token_type) = ($1, $1, '');
1270 3         5 next;
1271             }
1272             }
1273             }
1274              
1275 5418 100       16455 if ($c1 eq 'q') {
    100          
    100          
    100          
    100          
1276 206         748 my $quotelike_re = $c->quotelike_re;
1277 206 100       2443 if ($$rstr =~ m{\G((?:$quotelike_re)\b(?!\s*=>))}gc) {
    100          
    50          
    100          
1278 96 50       310 if (my $quotelike = $self->_match_quotelike($c, $rstr, $1)) {
1279 96         223 ($token, $token_desc, $token_type) = ($quotelike, 'STRING', 'STRING');
1280 96         255 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 92 50       558 if (my $quotelike = $self->_match_quotelike($c, $rstr, $1)) {
1287 92         266 ($token, $token_desc, $token_type) = ($quotelike, 'QUOTED_WORD_LIST', 'EXPR');
1288 92         309 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       63 if (my $regexp = $self->_match_regexp($c, $rstr)) {
1303 16         48 ($token, $token_desc, $token_type) = ($regexp, 'qr', 'EXPR');
1304 16         57 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 637 100       1881 if ($$rstr =~ m{\G(m\b(?!\s*=>))}gc) {
1312 31 50       123 if (my $regexp = $self->_match_regexp($c, $rstr)) {
1313 31         82 ($token, $token_desc, $token_type) = ($regexp, 'm', 'EXPR');
1314 31         59 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 591 100       1869 if ($$rstr =~ m{\G(s\b(?!\s*=>))}gc) {
1322 53 50       192 if (my $regexp = $self->_match_substitute($c, $rstr)) {
1323 53         136 ($token, $token_desc, $token_type) = ($regexp, 's', 'EXPR');
1324 53         103 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       58 if (my $trans = $self->_match_transliterate($c, $rstr)) {
1333 3         8 ($token, $token_desc, $token_type) = ($trans, 'tr', 'EXPR');
1334 3         8 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       16 if ($$rstr =~ m{\G(y\b(?!\s*=>))}gc) {
1342 2 50       6 if (my $trans = $self->_match_transliterate($c, $rstr)) {
1343 2         7 ($token, $token_desc, $token_type) = ($trans, 'y', 'EXPR');
1344 2         3 next;
1345             } else {
1346 0         0 _debug("TRANSLITERATE ERROR: $@") if DEBUG;
1347 0         0 pos($$rstr) = $pos;
1348             }
1349             }
1350             }
1351             }
1352              
1353 6702 100       18856 if ($$rstr =~ m{\G(\w+)}gc) {
1354 5987         12099 $token = $1;
1355 5987 100 66     21241 if ($prev_token_type eq 'ARROW') {
    100 66        
    100          
    100          
1356 521 100       1553 $$rstr =~ m{\G((?:(?:::|')\w+)+)\b}gc and $token .= $1;
1357 521         1087 ($token_desc, $token_type) = ('METHOD', 'METHOD');
1358             } elsif ($token eq 'CORE') {
1359 3         7 ($token_desc, $token_type) = ('NAMESPACE', 'WORD');
1360             } elsif ($token eq 'format') {
1361 5 100       24 if ($$rstr =~ m{\G([^=]*?=[ \t]*\n.*?\n\.\n)}gcs) {
1362 4         12 $token .= $1;
1363 4         8 ($token_desc, $token_type) = ('FORMAT', '');
1364 4         7 $current_scope |= F_STATEMENT_END|F_EXPR_END;
1365 4         4 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 3505 100       8415 if ($c->token_is_op_keyword($token)) {
1369 164         341 ($token_desc, $token_type) = ($token, 'OP');
1370             } else {
1371 3341         6004 ($token_desc, $token_type) = ('KEYWORD', 'KEYWORD');
1372 3341         8382 $c->check_new_keyword($token);
1373 3341 100       8919 push @keywords, $token unless $token eq 'undef';
1374             }
1375             } else {
1376 1953 100 100     4626 if ($c1 eq 'v' and $token =~ /^v(?:0|[1-9][0-9]*)$/) {
1377 5 50       32 if ($$rstr =~ m{\G((?:\.[0-9][0-9_]*)+)}gc) {
1378 5         18 $token .= $1;
1379 5         14 ($token_desc, $token_type) = ('VERSION_STRING', 'EXPR');
1380 5         11 next;
1381             }
1382             }
1383 1948 100       6984 $$rstr =~ m{\G((?:(?:::|')\w+)+)\b}gc and $token .= $1;
1384 1948         4281 ($token_desc, $token_type) = ('WORD', 'WORD');
1385 1948 100       3573 if ($prepend) {
1386 49         130 $token = "$prepend$token";
1387 49 100 66     185 pop @tokens if @tokens and $tokens[-1][0] eq $prepend;
1388 49 100 66     207 pop @scope_tokens if @scope_tokens and $scope_tokens[-1][0] eq $prepend;
1389             }
1390             }
1391 5978         9912 next;
1392             }
1393              
1394             # ignore control characters
1395 715 50       1885 if ($$rstr =~ m{\G([[:cntrl:]]+)}gc) {
1396 0         0 next;
1397             }
1398              
1399 715 100       1872 if ($$rstr =~ m{\G([[:ascii:]]+)}gc) {
1400 1 50       5 last if $parent_scope & F_STRING_EVAL;
1401 0         0 _error("UNKNOWN: $1");
1402 0         0 push @{$c->{errors}}, qq{"$1"};
  0         0  
1403 0         0 $token = $1;
1404 0         0 next;
1405             }
1406 714 50       1789 if ($$rstr =~ m{\G([[:^ascii:]](?:[[:^ascii:]]|\w)*)}gc) {
1407 0 0       0 if (!$c->{utf8}) {
1408 0 0       0 last if $parent_scope & F_STRING_EVAL;
1409 0         0 _error("UNICODE?: $1");
1410 0         0 push @{$c->{errors}}, qq{"$1"};
  0         0  
1411             } else {
1412 0         0 _debug("UTF8: $1") if DEBUG;
1413             }
1414 0         0 $token = $1;
1415 0         0 next;
1416             }
1417 714 50       1776 if ($$rstr =~ m{\G(\S+)}gc) {
1418 0 0       0 last if $parent_scope & F_STRING_EVAL;
1419 0         0 _error("UNEXPECTED: $1");
1420 0         0 push @{$c->{errors}}, qq{"$1"};
  0         0  
1421 0         0 $token = $1;
1422             }
1423              
1424 714         1217 last;
1425             } continue {
1426 45599 50       76457 die "Aborted at $prev_pos" if $prev_pos == pos($$rstr);
1427 45599         57465 $prev_pos = pos($$rstr);
1428              
1429 45599 100       69206 if (defined $token) {
1430 26559 100 66     92821 if (!($current_scope & F_EXPR)) {
    100 33        
1431 5925         6863 _debug('BEGIN EXPR') if DEBUG;
1432 5925         8038 $current_scope |= F_EXPR;
1433             } 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 '=>'))) {
1434 3343         5348 @keywords = ();
1435 3343         4002 _debug('END EXPR') if DEBUG;
1436 3343         4273 $current_scope &= MASK_EXPR_END;
1437             }
1438 26559         33787 $prepend = undef;
1439              
1440 26559         30489 if (DEBUG) {
1441             my $token_str = ref $token ? Data::Dump::dump($token) : $token;
1442             _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' : ''));
1443             }
1444              
1445 26559 100       41585 if ($parent_scope & F_KEEP_TOKENS) {
1446 841         2106 push @scope_tokens, [$token, $token_desc];
1447 841 100 66     2706 if ($token eq '-' or $token eq '+') {
1448 39         62 $prepend = $token;
1449             }
1450             }
1451 26559 100 100     114505 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        
1452 979         1478 $current_scope |= F_KEEP_TOKENS;
1453             }
1454 26559 100       56916 if ($c->token_expects_block($token)) {
1455 1091         1657 $waiting_for_a_block = 1;
1456             }
1457 26559 100 100     61493 if ($current_scope & F_EVAL or ($parent_scope & F_EVAL and (!@{$c->{stack}} or $c->{stack}[-1][0] ne '{'))) {
      100        
      100        
1458 134 100       503 if ($token_type eq 'STRING') {
    100          
    100          
1459 32 100       216 if ($token->[0] =~ /\b(?:(?:use|no)\s+[A-Za-z]|require\s+(?:q[qw]?.|['"])?[A-Za-z])/) {
1460 20         46 my $eval_string = $token->[0];
1461 20 50 33     123 if (defined $eval_string and $eval_string ne '') {
1462 20         65 $eval_string =~ s/\\(.)/$1/g;
1463 20         58 pos($eval_string) = 0;
1464 20         52 $c->{eval} = 1;
1465 20         47 my $saved_stack = $c->{stack};
1466 20         50 $c->{stack} = [];
1467 20         40 eval { $self->_scan($c, \$eval_string, (
  20         256  
1468             ($current_scope | $parent_scope | F_STRING_EVAL) &
1469             F_RESCAN
1470             ))};
1471 20         58 $c->{stack} = $saved_stack;
1472             }
1473             }
1474 32         65 $current_scope &= MASK_EVAL;
1475             } elsif ($token_desc eq 'HEREDOC') {
1476 1 50       11 if ($token->[0] =~ /\b(?:use|require|no)\s+[A-Za-z]/) {
1477 1         3 my $eval_string = $token->[0];
1478 1 50 33     8 if (defined $eval_string and $eval_string ne '') {
1479 1         3 $eval_string =~ s/\\(.)/$1/g;
1480 1         4 pos($eval_string) = 0;
1481 1         3 $c->{eval} = 1;
1482 1         3 my $saved_stack = $c->{stack};
1483 1         4 $c->{stack} = [];
1484 1         2 eval { $self->_scan($c, \$eval_string, (
  1         6  
1485             ($current_scope | $parent_scope | F_STRING_EVAL) &
1486             F_RESCAN
1487             ))};
1488 1         5 $c->{stack} = $saved_stack;
1489             }
1490             }
1491 1         2 $current_scope &= MASK_EVAL;
1492             } elsif ($token_type eq 'VARIABLE') {
1493 8         98 $current_scope &= MASK_EVAL;
1494             }
1495 134 100       401 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
1496             }
1497 26559 100       44208 if ($token eq 'eval') {
1498 51         98 $current_scope |= F_EVAL;
1499 51         172 $c->{eval} = 1;
1500             }
1501              
1502 26559 100       41253 if ($current_scope & F_KEEP_TOKENS) {
1503 4129         9929 push @tokens, [$token, $token_desc];
1504 4129 100 100     11923 if ($token eq '-' or $token eq '+') {
1505 12         41 $prepend = $token;
1506             }
1507 4129 100 100     9047 if ($token_type eq 'KEYWORD' and $has_sideff{$token}) {
1508 11         26 $current_scope |= F_SIDEFF;
1509             }
1510             }
1511 26559 100       40997 if ($stack) {
1512 2289         3212 push @{$c->{stack}}, $stack;
  2289         4709  
1513 2289         3114 _dump_stack($c, $stack->[0]) if DEBUG;
1514 2289         3375 my $child_scope = $current_scope | $parent_scope;
1515 2289 100 100     6472 if ($token eq '{' and $is_conditional{$stack->[2]}) {
1516 271         408 $child_scope |= F_CONDITIONAL
1517             }
1518 2289         20084 my $scanned_tokens = $self->_scan($c, $rstr, (
1519             $child_scope & F_RESCAN
1520             ));
1521 2289 100 100     5967 if ($token eq '{' and $current_scope & F_EVAL) {
1522 16         32 $current_scope &= MASK_EVAL;
1523 16 50       53 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
1524             }
1525 2289 100       5522 if ($current_scope & F_KEEP_TOKENS) {
    100          
1526 139   50     369 my $start = pop @tokens || '';
1527 139   50     406 my $end = pop @$scanned_tokens || '';
1528 139         561 push @tokens, [$scanned_tokens, "$start->[0]$end->[0]"];
1529             } elsif ($parent_scope & F_KEEP_TOKENS) {
1530 36   50     109 my $start = pop @scope_tokens || '';
1531 36   50     83 my $end = pop @$scanned_tokens || '';
1532 36         135 push @scope_tokens, [$scanned_tokens, "$start->[0]$end->[0]"];
1533             }
1534              
1535 2289 100 100     8525 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        
1536 302         535 pop @keywords;
1537             }
1538              
1539 2289 100 100     7073 if ($stack->[0] eq '{' and @keywords and $c->token_expects_block($keywords[0]) and !$c->token_expects_block_list($keywords[-1])) {
      100        
      100        
1540 611 50 0     1600 $current_scope |= F_STATEMENT_END unless @tokens and ($c->token_defines_sub($keywords[-1]) or $keywords[-1] eq 'eval');
      33        
1541             }
1542 2289         4626 $stack = undef;
1543             }
1544 26559 100       42081 if ($current_scope & F_STATEMENT_END) {
1545 4273 100 66     9454 if (($current_scope & F_KEEP_TOKENS) and @tokens) {
1546 944         1927 my $first_token = $tokens[0][0];
1547 944 100       2127 if ($first_token eq '->') {
1548 46         101 $first_token = $tokens[1][0];
1549             # ignore ->use and ->no
1550             # ->require may be from UNIVERSAL::require
1551 46 100 66     198 if ($first_token eq 'use' or $first_token eq 'no') {
1552 1         2 $first_token = '';
1553             }
1554             }
1555 944 100       2256 my $cond = (($current_scope | $parent_scope) & (F_CONDITIONAL|F_SIDEFF)) ? 1 : 0;
1556 944 100       2332 if (exists $c->{callback}{$first_token}) {
1557 713         1856 $c->{current_scope} = \$current_scope;
1558 713         1831 $c->{cond} = $cond;
1559 713         2691 $c->{callback}{$first_token}->($c, $rstr, \@tokens);
1560              
1561 713 50 33     2247 if ($c->{found_unsupported_package} and !$c->{quick}) {
1562 0         0 my $unsupported = $c->{found_unsupported_package};
1563 0         0 $c->{quick} = 1;
1564 0         0 $self->_skim_string($c, $rstr);
1565 0         0 warn "Unsupported package '$unsupported' is found. Result may be incorrect.\n";
1566             }
1567             }
1568 944 100       2405 if (exists $c->{keyword}{$first_token}) {
1569 185         466 $c->{current_scope} = \$current_scope;
1570 185         497 $c->{cond} = $cond;
1571 185         352 $tokens[0][1] = 'KEYWORD';
1572 185         542 $c->run_callback_for(keyword => $first_token, \@tokens);
1573             }
1574 944 100 66     4216 if (exists $c->{method}{$first_token} and $caller_package) {
1575 18         51 unshift @tokens, [$caller_package, 'WORD'];
1576 18         53 $c->{current_scope} = \$current_scope;
1577 18         30 $c->{cond} = $cond;
1578 18         66 $c->run_callback_for(method => $first_token, \@tokens);
1579             }
1580 944 100       3540 if ($current_scope & F_SIDEFF) {
1581 11         20 $current_scope &= MASK_SIDEFF;
1582 11         65 while(my $token = shift @tokens) {
1583 58 100       166 last if $has_sideff{$token->[0]};
1584             }
1585 11 100       36 $current_scope &= F_SIDEFF if grep {$has_sideff{$_->[0]}} @tokens;
  46         99  
1586 11 50       30 if (@tokens) {
1587 11         25 $first_token = $tokens[0][0];
1588 11 100       38 $cond = (($current_scope | $parent_scope) & (F_CONDITIONAL|F_SIDEFF)) ? 1 : 0;
1589 11 50       46 if (exists $c->{callback}{$first_token}) {
1590 0         0 $c->{current_scope} = \$current_scope;
1591 0         0 $c->{cond} = $cond;
1592 0         0 $c->{callback}{$first_token}->($c, $rstr, \@tokens);
1593             }
1594 11 100       43 if (exists $c->{keyword}{$first_token}) {
1595 1         3 $c->{current_scope} = \$current_scope;
1596 1         2 $c->{cond} = $cond;
1597 1         2 $tokens[0][1] = 'KEYWORD';
1598 1         4 $c->run_callback_for(keyword => $first_token, \@tokens);
1599             }
1600 11 50 33     102 if (exists $c->{method}{$first_token} and $caller_package) {
1601 0         0 unshift @tokens, [$caller_package, 'WORD'];
1602 0         0 $c->{current_scope} = \$current_scope;
1603 0         0 $c->{cond} = $cond;
1604 0         0 $c->run_callback_for(method => $first_token, \@tokens);
1605             }
1606             }
1607             }
1608             }
1609 4273         6746 @tokens = ();
1610 4273         5877 @keywords = ();
1611 4273         5498 $current_scope &= MASK_STATEMENT_END;
1612 4273         5412 $caller_package = undef;
1613 4273         6502 $token = $token_type = '';
1614 4273         5113 _debug('END SENTENSE') if DEBUG;
1615             }
1616 26559 100 100     44138 if ($unstack and @{$c->{stack}}) {
  2215         5737  
1617 2193         3040 my $stacked = pop @{$c->{stack}};
  2193         4049  
1618 2193         4605 my $stacked_type = substr($stacked->[0], -1);
1619 2193 50 66     13177 if (
      66        
      33        
      66        
      33        
1620             ($unstack eq '}' and $stacked_type ne '{') or
1621             ($unstack eq ']' and $stacked_type ne '[') or
1622             ($unstack eq ')' and $stacked_type ne '(')
1623             ) {
1624 0   0     0 my $prev_pos = $stacked->[1] || 0;
1625 0         0 die "mismatch $stacked_type $unstack\n" .
1626             substr($$rstr, $prev_pos, pos($$rstr) - $prev_pos);
1627             }
1628 2193         2827 _dump_stack($c, $unstack) if DEBUG;
1629 2193         2999 $current_scope |= F_SCOPE_END;
1630 2193         3532 $unstack = undef;
1631             }
1632              
1633 26559 100       41819 last if $current_scope & F_SCOPE_END;
1634 24293 100       38501 last if $c->{ended};
1635 24188 50 33     41040 last if $c->{last_found_by_skimming} and $c->{last_found_by_skimming} < pos($$rstr);
1636              
1637 24188         39251 ($prev_token, $prev_token_type) = ($token, $token_type);
1638             }
1639              
1640 43228 50 33     50952 if (@{$c->{errors}} and !($parent_scope & F_STRING_EVAL)) {
  43228         105476  
1641 0         0 my $rest = substr($$rstr, pos($$rstr));
1642 0 0       0 _error("REST:\n\n".$rest) if $rest;
1643 0         0 last;
1644             }
1645             }
1646              
1647 3087 100       5857 if (@tokens) {
1648 40 50       128 if (my $first_token = $tokens[0][0]) {
1649 40 100       165 if (exists $c->{callback}{$first_token}) {
1650 28         105 $c->{callback}{$first_token}->($c, $rstr, \@tokens);
1651             }
1652 40 100       122 if (exists $c->{keyword}{$first_token}) {
1653 9         16 $tokens[0][1] = 'KEYWORD';
1654 9         29 $c->run_callback_for(keyword => $first_token, \@tokens);
1655             }
1656             }
1657             }
1658              
1659 3087         4136 _dump_stack($c, "END SCOPE") if DEBUG;
1660              
1661 3087         7876 \@scope_tokens;
1662             }
1663              
1664             sub _match_quotelike {
1665 188     188   664 my ($self, $c, $rstr, $op) = @_;
1666              
1667             # '#' only works when it comes just after the op,
1668             # without prepending spaces
1669 188         1905 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1670              
1671 188 50       708 unless ($$rstr =~ m/\G(\S)/gc) {
1672 0         0 return _match_error($rstr, "No block delimiter found after $op");
1673             }
1674 188         413 my $ldel = $1;
1675 188         347 my $startpos = pos($$rstr);
1676              
1677 188 100       653 if ($ldel =~ /[[(<{]/) {
1678 135         376 my ($rdel, $re_skip) = _gen_rdel_and_re_skip($ldel);
1679 135         344 my @nest = ($ldel);
1680 135         238 my ($p, $c1);
1681 135         367 while(defined($p = pos($$rstr))) {
1682 360         681 $c1 = substr($$rstr, $p, 1);
1683 360 100       664 if ($c1 eq '\\') {
1684 28         55 pos($$rstr) = $p + 2;
1685 28         50 next;
1686             }
1687 332 100       697 if ($c1 eq $ldel) {
1688 15         35 pos($$rstr) = $p + 1;
1689 15         50 push @nest, $ldel;
1690 15         31 next;
1691             }
1692 317 100       599 if ($c1 eq $rdel) {
1693 150         343 pos($$rstr) = $p + 1;
1694 150         302 pop @nest;
1695 150 100       413 last unless @nest;
1696 15         28 next;
1697             }
1698 167 50       1487 $$rstr =~ m{\G$re_skip}gc and next;
1699 0         0 last;
1700             }
1701 135 50       412 return if @nest;
1702             } else {
1703 53         169 my $re = _gen_re_str_in_delims_with_end_delim($ldel);
1704 53 50       772 $$rstr =~ /\G$re/gcs or return;
1705             }
1706              
1707 188         408 my $endpos = pos($$rstr);
1708              
1709 188         1002 return [substr($$rstr, $startpos, $endpos - $startpos - 1), $op];
1710             }
1711              
1712             sub _match_regexp0 { # //
1713 98     98   277 my ($self, $c, $rstr, $startpos, $token_type) = @_;
1714 98         276 pos($$rstr) = $startpos + 1;
1715              
1716 98         376 my $re_shortcut = _gen_re_regexp_shortcut('/');
1717 98 100 100     1233 $$rstr =~ m{\G$re_shortcut}gcs or # shortcut
    100          
1718             defined($self->_scan_re($c, $rstr, '/', '/', $token_type ? 'm' : '')) or return _match_error($rstr, "Closing delimiter was not found: $@");
1719              
1720 97         340 $$rstr =~ m/\G([msixpodualgc]*)/gc;
1721 97         214 my $mod = $1;
1722              
1723 97         182 my $endpos = pos($$rstr);
1724              
1725 97         282 my $re = substr($$rstr, $startpos, $endpos - $startpos);
1726 97 100 100     399 if ($re =~ /\n/s and $mod !~ /x/) {
1727 1         8 return _match_error($rstr, "multiline without x");
1728             }
1729 96         315 return $re;
1730             }
1731              
1732             sub _match_regexp {
1733 47     47   218 my ($self, $c, $rstr) = @_;
1734 47   50     228 my $startpos = pos($$rstr) || 0;
1735              
1736             # '#' only works when it comes just after the op,
1737             # without prepending spaces
1738 47         497 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1739              
1740 47 50       183 unless ($$rstr =~ m/\G(\S)/gc) {
1741 0         0 return _match_error($rstr, "No block delimiter found");
1742             }
1743 47         156 my ($ldel, $rdel) = ($1, $1);
1744              
1745 47 100       154 if ($ldel =~ /[[(<{]/) {
1746 27         66 $rdel =~ tr/[({/;
1747             }
1748              
1749 47         212 my $re_shortcut = _gen_re_regexp_shortcut($ldel, $rdel);
1750 47 50 66     1411 $$rstr =~ m{\G$re_shortcut}gcs or # shortcut
1751             defined($self->_scan_re($c, $rstr, $ldel, $rdel, 'm/qr')) or return _match_error($rstr, "Closing delimiter was not found: $@");
1752              
1753             # strictly speaking, qr// doesn't support gc.
1754 47         183 $$rstr =~ m/\G[msixpodualgc]*/gc;
1755 47         96 my $endpos = pos($$rstr);
1756              
1757 47         199 return substr($$rstr, $startpos, $endpos - $startpos);
1758             }
1759              
1760             sub _match_substitute {
1761 53     53   115 my ($self, $c, $rstr) = @_;
1762 53   50     143 my $startpos = pos($$rstr) || 0;
1763              
1764             # '#' only works when it comes just after the op,
1765             # without prepending spaces
1766 53         561 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1767              
1768 53 50       191 unless ($$rstr =~ m/\G(\S)/gc) {
1769 0         0 return _match_error($rstr, "No block delimiter found");
1770             }
1771 53         174 my ($ldel1, $rdel1) = ($1, $1);
1772              
1773 53 100       175 if ($ldel1 =~ /[[(<{]/) {
1774 22         94 $rdel1 =~ tr/[({/;
1775             }
1776              
1777 53         141 my $re_shortcut = _gen_re_regexp_shortcut($ldel1, $rdel1);
1778 53 50 100     1385 ($ldel1 ne '\\' and $$rstr =~ m{\G$re_shortcut}gcs) or # shortcut
      66        
1779             defined($self->_scan_re($c, $rstr, $ldel1, $rdel1, 's')) or return _match_error($rstr, "Closing delimiter was not found: $@");
1780 53 50       202 defined($self->_scan_re2($c, $rstr, $ldel1, 's')) or return;
1781 53         156 $$rstr =~ m/\G[msixpodualgcer]*/gc;
1782 53         83 my $endpos = pos($$rstr);
1783              
1784 53         198 return substr($$rstr, $startpos, $endpos - $startpos);
1785             }
1786              
1787             sub _match_transliterate {
1788 5     5   18 my ($self, $c, $rstr) = @_;
1789 5   50     16 my $startpos = pos($$rstr) || 0;
1790              
1791             # '#' only works when it comes just after the op,
1792             # without prepending spaces
1793 5         93 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1794              
1795 5 50       23 unless ($$rstr =~ m/\G(\S)/gc) {
1796 0         0 return _match_error($rstr, "No block delimiter found");
1797             }
1798 5         17 my $ldel1 = $1;
1799 5         8 my $ldel2;
1800              
1801 5 100       18 if ($ldel1 =~ /[[(<{]/) {
1802 1         4 (my $rdel1 = $ldel1) =~ tr/[({/;
1803 1         4 my $re = _gen_re_str_in_delims_with_end_delim($rdel1);
1804 1 50       43 $$rstr =~ /\G$re/gcs or return;
1805 1         24 $$rstr =~ /\G(?:$re_comment)/gcs;
1806 1 50       7 unless ($$rstr =~ /\G\s*(\S)/gc) {
1807 0         0 return _match_error($rstr, "Missing second block");
1808             }
1809 1         3 $ldel2 = $1;
1810             } else {
1811 4         14 my $re = _gen_re_str_in_delims_with_end_delim($ldel1);
1812 4 50       126 $$rstr =~ /\G$re/gcs or return;
1813 4         13 $ldel2 = $ldel1;
1814             }
1815              
1816 5 100       25 if ($ldel2 =~ /[[(<{]/) {
1817 1         4 (my $rdel2 = $ldel2) =~ tr/[({/;
1818 1         3 my $re = _gen_re_str_in_delims_with_end_delim($rdel2);
1819 1 50       23 $$rstr =~ /\G$re/gcs or return;
1820             } else {
1821 4         12 my $re = _gen_re_str_in_delims_with_end_delim($ldel2);
1822 4 50       87 $$rstr =~ /\G$re/gcs or return;
1823             }
1824              
1825 5         19 $$rstr =~ m/\G[cdsr]*/gc;
1826 5         12 my $endpos = pos($$rstr);
1827              
1828 5         40 return substr($$rstr, $startpos, $endpos - $startpos);
1829             }
1830              
1831             sub _match_heredoc {
1832 16     16   37 my ($self, $c, $rstr) = @_;
1833              
1834 16   50     40 my $startpos = pos($$rstr) || 0;
1835              
1836 16         70 $$rstr =~ m{\G(?:<<(~)?\s*)}gc;
1837 16 100       52 my $indent = $1 ? "\\s*" : "";
1838              
1839 16         34 my $label;
1840 16 100       357 if ($$rstr =~ m{\G\\?([A-Za-z_]\w*)}gc) {
    50          
1841 8         17 $label = $1;
1842             } elsif ($$rstr =~ m{
1843             \G ' ($re_str_in_single_quotes) '
1844             | \G " ($re_str_in_double_quotes) "
1845             | \G ` ($re_str_in_backticks) `
1846             }gcsx) {
1847 8         53 $label = $+;
1848             } else {
1849 0         0 return;
1850             }
1851 16         46 $label =~ s/\\(.)/$1/g;
1852 16         28 my $extrapos = pos($$rstr);
1853 16         52 $$rstr =~ m{\G.*\n}gc;
1854 16         52 my $str1pos = pos($$rstr)--;
1855 16 100       358 unless ($$rstr =~ m{\G.*?\n$indent(?=\Q$label\E\n)}gcs) {
1856 2         8 return _match_error($rstr, qq{Missing here doc terminator ('$label')});
1857             }
1858 14         41 my $ldpos = pos($$rstr);
1859 14         152 $$rstr =~ m{\G\Q$label\E\n}gc;
1860 14         35 my $ld2pos = pos($$rstr);
1861              
1862 14         91 my $heredoc = [
1863             substr($$rstr, $str1pos, $ldpos-$str1pos),
1864             substr($$rstr, $startpos, $extrapos-$startpos),
1865             substr($$rstr, $ldpos, $ld2pos-$ldpos),
1866             ];
1867 14         131 substr($$rstr, $str1pos, $ld2pos - $str1pos) = '';
1868 14         104 pos($$rstr) = $extrapos;
1869 14 100       43 if ($indent) {
1870 1         11 $c->add_perl('5.026', '<<~');
1871             }
1872 14         54 return $heredoc;
1873             }
1874              
1875             sub _scan_re {
1876 126     126   491 my ($self, $c, $rstr, $ldel, $rdel, $op) = @_;
1877 126   50     331 my $startpos = pos($$rstr) || 0;
1878              
1879 126         220 _debug(" L $ldel R $rdel") if DEBUG_RE;
1880              
1881 126         210 my ($outer_opening_delimiter, $outer_closing_delimiter);
1882 126 100       237 if (@{$c->{stack}}) {
  126         446  
1883 110         363 ($outer_closing_delimiter = $outer_opening_delimiter = $c->{stack}[-1][0]) =~ tr/[({/;
1884             }
1885              
1886 126         326 my @nesting = ($ldel);
1887 126         199 my $multiline = 0;
1888 126         186 my $saw_sharp = 0;
1889 126         166 my $prev;
1890 126         249 my ($p, $c1);
1891 126         326 while (defined($p = pos($$rstr))) {
1892 5053         7215 $c1 = substr($$rstr, $p, 1);
1893 5053 100       7815 if ($c1 eq "\n") {
1894 271         603 $$rstr =~ m{\G\n\s*}gcs;
1895 271         351 $multiline = 1;
1896 271         314 $saw_sharp = 0;
1897             # _debug("CRLF") if DEBUG_RE;
1898 271         533 next;
1899             }
1900 4782 100 66     11089 if ($c1 eq ' ' or $c1 eq "\t") {
1901 696         1177 $$rstr =~ m{\G\s*}gc;
1902             # _debug("WHITESPACE") if DEBUG_RE;
1903 696         1232 next;
1904             }
1905 4086 100 100     6867 if ($c1 eq '#' and $rdel ne '#') {
1906 144 100 100     856 if ($multiline and $$rstr =~ m{\G(#[^\Q$rdel\E]*?)\n}gcs) {
1907 94         139 _debug(" comment $1") if DEBUG_RE
1908             } else {
1909 50         156 pos($$rstr) = $p + 1;
1910 50         152 $saw_sharp = 1;
1911 50         73 _debug(" saw #") if DEBUG_RE;
1912             }
1913 144         290 next;
1914             }
1915              
1916 3942 100 100     7217 if ($c1 eq '\\' and $rdel ne '\\') {
1917 416 50       1108 if ($$rstr =~ m/\G(\\.)/gcs) {
1918 416         568 _debug(" escaped $1") if DEBUG_RE;
1919 416         736 next;
1920             }
1921             }
1922              
1923 3526         4012 _debug(" looking @nesting: $c1") if DEBUG_RE;
1924              
1925 3526 100       5457 if ($c1 eq '[') {
1926             # character class may have other (ignorable) delimiters
1927 197 50       525 if ($$rstr =~ m/\G(\[\[:\w+?:\]\])/gcs) {
1928 0         0 _debug(" character class $1") if DEBUG_RE;
1929 0         0 next;
1930             }
1931 197 100       666 if ($$rstr =~ m/\G(\[[^\\\]]]*?(\\.[^\\\]]]*)*\])/gcs) {
1932 59         76 _debug(" character class: $1") if DEBUG_RE;
1933 59         99 next;
1934             }
1935             }
1936              
1937 3467 100       6354 if ($c1 eq $rdel) {
    100          
1938 156         407 pos($$rstr) = $p + 1;
1939 156 100       361 if ($saw_sharp) {
1940 39         79 my $tmp_pos = $p + 1;
1941 39 100       63 if ($op eq 's') {
1942 3         6 _debug(" looking for latter part") if DEBUG_RE;
1943 3         13 my $latter = $self->_scan_re2($c, $rstr, $ldel, $op);
1944 3 50       11 if (!defined $latter) {
1945 0         0 pos($$rstr) = $tmp_pos;
1946 0         0 next;
1947             }
1948 3         4 _debug(" latter: $latter") if DEBUG_RE;
1949             }
1950 39 100       130 if ($$rstr =~ m/\G[a-wyz]*x/) {
1951             # looks like an end of block
1952 2         4 _debug(" end of block $rdel (after #)") if DEBUG_RE;
1953 2         5 @nesting = ();
1954 2         8 pos($$rstr) = $tmp_pos;
1955 2         6 last;
1956             }
1957 37         71 pos($$rstr) = $tmp_pos;
1958 37 100       69 if ($multiline) {
1959 29         55 next; # part of a comment
1960             }
1961             }
1962 125         250 _debug(" end of block $rdel") if DEBUG_RE;
1963 125         215 my $expected = $rdel;
1964 125 100       264 if ($ldel ne $rdel) {
1965 44         79 $expected =~ tr/)}]>/({[
1966             }
1967 125         341 while(my $nested = pop @nesting) {
1968 129 100       297 last if $nested eq $expected;
1969             }
1970 125 100       330 last unless @nesting;
1971 2         4 next;
1972             } elsif ($c1 eq $ldel) {
1973 30         65 pos($$rstr) = $p + 1;
1974 30 100 66     91 if ($multiline and $saw_sharp) {
1975             } else {
1976 2         5 _debug(" block $ldel") if DEBUG_RE;
1977 2         4 push @nesting, $ldel;
1978 2         5 next;
1979             }
1980             }
1981              
1982 3309 100       5070 if ($c1 eq '{') {
1983             # quantifier shouldn't be nested
1984 45 100       146 if ($$rstr =~ m/\G(\{[0-9]+(?:,(?:[0-9]+)?)?})/gcs) {
1985 4         7 _debug(" quantifier $1") if DEBUG_RE;
1986 4         7 next;
1987             }
1988             }
1989              
1990 3305 100       5130 if ($c1 eq '(') {
1991 407         694 my $c2 = substr($$rstr, $p + 1, 1);
1992 407 100 100     1315 if ($c2 eq '?' and !($multiline and $saw_sharp)) {
      100        
1993             # code
1994 209 100       680 if ($$rstr =~ m/\G((\()\?+?)(?=\{)/gc) {
1995 70         98 _debug(" code $1") if DEBUG_RE;
1996 70         165 push @nesting, $2;
1997 70 50       113 unless (eval { $self->_scan($c, $rstr, F_EXPECTS_BRACKET); 1 }) {
  70         220  
  70         152  
1998 0         0 _debug("scan failed") if DEBUG_RE;
1999 0         0 return;
2000             }
2001 70         169 next;
2002             }
2003             # comment
2004 139 100       329 if ($$rstr =~ m{\G(\(\?\#[^\\\)]*(?:\\.[^\\\)]*)*\))}gcs) {
2005 10         15 _debug(" comment $1") if DEBUG_RE;
2006 10         18 next;
2007             }
2008             }
2009              
2010             # grouping may have (ignorable) <>
2011 327 50       999 if ($$rstr =~ m/\G((\()(?:<[!=]|<\w+?>|>)?)/gc) {
2012 327         456 _debug(" group $1") if DEBUG_RE;
2013 327         750 push @nesting, $2;
2014 327         637 next;
2015             }
2016             }
2017              
2018             # maybe variables (maybe not)
2019 2898 100 100     5071 if ($c1 eq '$' and substr($$rstr, $p + 1, 1) eq '{') {
2020 3         7 my @tmp_stack = @{$c->{stack}};
  3         10  
2021 3 50       8 next if eval { $self->_scan($c, $rstr, F_EXPECTS_BRACKET); 1 };
  3         11  
  3         12  
2022 0         0 pos($$rstr) = $p;
2023 0         0 $c->{stack} = \@tmp_stack;
2024             }
2025              
2026 2895 100       4357 if ($c1 eq ')') {
2027 397 100 66     1301 if (@nesting and $nesting[-1] eq '(') {
2028 393         499 _debug(" end of group $c1") if DEBUG_RE;
2029 393         553 pop @nesting;
2030 393         843 pos($$rstr) = $p + 1;
2031 393         797 next;
2032             } else {
2033             # die "unnested @nesting" unless $saw_sharp;
2034             }
2035             }
2036              
2037             # for //, see if an outer closing delimiter is found first (ie. see if it was actually a /)
2038 2502 100       3705 if (!$op) {
2039 87 100 66     197 if ($outer_opening_delimiter and $c1 eq $outer_opening_delimiter) {
2040 1         4 push @nesting, $c1;
2041 1         4 pos($$rstr) = $p + 1;
2042 1         3 next;
2043             }
2044              
2045 86 100 66     1113 if ($outer_closing_delimiter and $c1 eq $outer_closing_delimiter) {
2046 2 100 66     15 if (@nesting and $nesting[-1] eq $outer_opening_delimiter) {
2047 1         2 pop @nesting;
2048 1         2 pos($$rstr) = $p + 1;
2049 1         3 next;
2050             }
2051              
2052 1         10 return _match_error($rstr, "Outer closing delimiter: $outer_closing_delimiter is found");
2053             }
2054             }
2055              
2056 2499 50       5493 if ($$rstr =~ m/\G(\w+|.)/gcs) {
2057 2499         2897 _debug(" rest $1") if DEBUG_RE;
2058 2499         4251 next;
2059             }
2060 0         0 last;
2061             }
2062 125 50       421 if ($#nesting>=0) {
2063 0         0 return _match_error($rstr, "Unmatched opening bracket(s): ". join("..",@nesting)."..");
2064             }
2065              
2066 125         282 my $endpos = pos($$rstr);
2067              
2068 125         646 return substr($$rstr, $startpos, $endpos - $startpos);
2069             }
2070              
2071              
2072             sub _scan_re2 {
2073 56     56   153 my ($self, $c, $rstr, $ldel, $op) = @_;
2074 56         104 my $startpos = pos($$rstr);
2075              
2076 56 100       167 if ($ldel =~ /[[(<{]/) {
2077 23         141 $$rstr =~ /\G(?:$re_comment)/gcs;
2078              
2079 23 50       81 unless ($$rstr =~ /\G\s*(\S)/gc) {
2080 0         0 return _match_error($rstr, "Missing second block for quotelike $op");
2081             }
2082 23         53 $ldel = $1;
2083             }
2084              
2085 56 100       142 if ($ldel =~ /[[(<{]/) {
2086 23         53 my ($rdel, $re_skip) = _gen_rdel_and_re_skip($ldel);
2087 23         49 my @nest = $ldel;
2088 23         34 my ($p, $c1);
2089 23         52 while(defined($p = pos($$rstr))) {
2090 168         236 $c1 = substr($$rstr, $p, 1);
2091 168 100       277 if ($c1 eq '\\') {
2092 16         25 pos($$rstr) = $p + 2;
2093 16         33 next;
2094             }
2095 152 100       246 if ($c1 eq $ldel) {
2096 25         40 pos($$rstr) = $p + 1;
2097 25         37 push @nest, $ldel;
2098 25         42 next;
2099             }
2100 127 100       195 if ($c1 eq $rdel) {
2101 48         87 pos($$rstr) = $p + 1;
2102 48         68 pop @nest;
2103 48 100       397 last unless @nest;
2104 25         40 next;
2105             }
2106 79 50       352 $$rstr =~ m{\G$re_skip}gc and next;
2107 0         0 last;
2108             }
2109 23 50       52 return _match_error($rstr, "nesting mismatch: @nest") if @nest;
2110             } else {
2111 33         102 my $re = _gen_re_str_in_delims_with_end_delim($ldel);
2112 33 50       459 $$rstr =~ /\G$re/gcs or return;
2113             }
2114              
2115 56         120 my $endpos = pos($$rstr);
2116              
2117 56         207 return substr($$rstr, $startpos, $endpos - $startpos);
2118             }
2119              
2120             sub _use {
2121 641     641   1301 my ($c, $rstr, $tokens) = @_;
2122 641         902 _debug("USE TOKENS: ".(Data::Dump::dump($tokens))) if DEBUG;
2123 641         1184 shift @$tokens; # discard 'use' itself
2124              
2125             # TODO: see if the token is WORD or not?
2126 641 50       1839 my $name_token = shift @$tokens or return;
2127 641         1248 my $name = $name_token->[0];
2128 641 50 33     3207 return if !defined $name or ref $name or $name eq '';
      33        
2129              
2130 641         1617 my $c1 = substr($name, 0, 1);
2131 641 100       1551 if ($c1 eq '5') {
2132 3         16 $c->add(perl => $name);
2133 3         246 return;
2134             }
2135 638 100       1380 if ($c1 eq 'v') {
2136 6         22 my $c2 = substr($name, 1, 1);
2137 6 100       34 if ($c2 eq '5') {
2138 1         4 $c->add(perl => $name);
2139 1         83 return;
2140             }
2141 5 50       17 if ($c2 eq '6') {
2142 0         0 $c->{perl6} = 1;
2143 0         0 $c->{ended} = 1;
2144 0         0 return;
2145             }
2146             }
2147 637 100       1927 if ($c->enables_utf8($name)) {
2148 18         58 $c->add($name => 0);
2149 18         387 $c->{utf8} = 1;
2150 18 100       42 if (!$c->{decoded}) {
2151 9         17 $c->{decoded} = 1;
2152 9         13 _debug("UTF8 IS ON") if DEBUG;
2153 9         147 utf8::decode($$rstr);
2154 9         100 pos($$rstr) = 0;
2155 9         26 $c->{ended} = $c->{redo} = 1;
2156             }
2157             }
2158              
2159 637 50       2226 if (is_module_name($name)) {
2160 637         1370 my $maybe_version_token = $tokens->[0];
2161 637         1061 my $maybe_version_token_desc = $maybe_version_token->[1];
2162 637 100 66     2880 if ($maybe_version_token_desc and ($maybe_version_token_desc eq 'NUMBER' or $maybe_version_token_desc eq 'VERSION_STRING')) {
      100        
2163 34         150 $c->add($name => $maybe_version_token->[0]);
2164 34         3624 shift @$tokens;
2165             } else {
2166 603         1900 $c->add($name => 0);
2167             }
2168              
2169 637 100       23200 if (exists $sub_keywords{$name}) {
2170 5         8 $c->register_sub_keywords(@{$sub_keywords{$name}});
  5         19  
2171 5         24 $c->prototype_re(qr{\G(\((?:[^\\\(\)]*(?:\\.[^\\\(\)]*)*)\))});
2172             }
2173 637 100       1678 if (exists $filter_modules{$name}) {
2174 1         3 my $tmp = pos($$rstr);
2175 1         3 my $redo = $filter_modules{$name}->($rstr);
2176 1         3 pos($$rstr) = $tmp;
2177 1 50       5 $c->{ended} = $c->{redo} = 1 if $redo;
2178             }
2179             }
2180              
2181 637 100       1878 if ($c->has_callback_for(use => $name)) {
    100          
2182 307         569 eval { $c->run_callback_for(use => $name, $tokens) };
  307         854  
2183 307 50       2227 warn "Callback Error: $@" if $@;
2184             } elsif ($name =~ /\b(?:Mo[ou]se?X?|MooX?|Elk|Antlers|Role)\b/) {
2185 2 50       10 my $module = $name =~ /Role/ ? 'Moose::Role' : 'Moose';
2186 2 100       6 if ($c->has_callback_for(use => $module)) {
2187 1         2 eval { $c->run_callback_for(use => $module, $tokens) };
  1         1080  
2188 1 50       4 warn "Callback Error: $@" if $@;
2189             }
2190             }
2191              
2192 637 50       2120 if (exists $unsupported_packages{$name}) {
2193 0         0 $c->{found_unsupported_package} = $name;
2194             }
2195             }
2196              
2197             sub _require {
2198 69     69   149 my ($c, $rstr, $tokens) = @_;
2199 69         99 _debug("REQUIRE TOKENS: ".(Data::Dump::dump($tokens))) if DEBUG;
2200 69         131 shift @$tokens; # discard 'require' itself
2201              
2202             # TODO: see if the token is WORD or not?
2203 69 50       215 my $name_token = shift @$tokens or return;
2204 69         141 my $name = $name_token->[0];
2205 69 100       165 if (ref $name) {
2206 7         15 $name = $name->[0];
2207 7 100       35 return if $name =~ /\.pl$/i;
2208              
2209 5         22 $name =~ s|/|::|g;
2210 5         29 $name =~ s|\.pm$||i;
2211             }
2212 67 50 33     336 return if !defined $name or $name eq '';
2213              
2214 67         151 my $c1 = substr($name, 0, 1);
2215 67 100       163 if ($c1 eq '5') {
2216 1         5 $c->add_conditional(perl => $name);
2217 1         112 return;
2218             }
2219 66 100       176 if ($c1 eq 'v') {
2220 1         3 my $c2 = substr($name, 1, 1);
2221 1 50       4 if ($c2 eq '5') {
2222 1         4 $c->add_conditional(perl => $name);
2223 1         130 return;
2224             }
2225 0 0       0 if ($c2 eq '6') {
2226 0         0 $c->{perl6} = 1;
2227 0         0 $c->{ended} = 1;
2228 0         0 return;
2229             }
2230             }
2231 65 100       252 if (is_module_name($name)) {
2232 62         267 $c->add_conditional($name => 0);
2233 62         2199 return;
2234             }
2235             }
2236              
2237             sub _no {
2238 31     31   81 my ($c, $rstr, $tokens) = @_;
2239 31         60 _debug("NO TOKENS: ".(Data::Dump::dump($tokens))) if DEBUG;
2240 31         64 shift @$tokens; # discard 'no' itself
2241              
2242             # TODO: see if the token is WORD or not?
2243 31 50       112 my $name_token = shift @$tokens or return;
2244 31         70 my $name = $name_token->[0];
2245 31 50 33     254 return if !defined $name or ref $name or $name eq '';
      33        
2246              
2247 31         80 my $c1 = substr($name, 0, 1);
2248 31 100       95 if ($c1 eq '5') {
2249 1         7 $c->add_no(perl => $name);
2250 1         150 return;
2251             }
2252 30 100       96 if ($c1 eq 'v') {
2253 1         5 my $c2 = substr($name, 1, 1);
2254 1 50       6 if ($c2 eq '5') {
2255 1         6 $c->add_no(perl => $name);
2256 1         164 return;
2257             }
2258 0 0       0 if ($c2 eq '6') {
2259 0         0 $c->{perl6} = 1;
2260 0         0 $c->{ended} = 1;
2261 0         0 return;
2262             }
2263             }
2264 29 50       99 if ($name eq 'utf8') {
2265 0         0 $c->{utf8} = 0;
2266             }
2267              
2268 29 50       147 if (is_module_name($name)) {
2269 29         64 my $maybe_version_token = $tokens->[0];
2270 29         54 my $maybe_version_token_desc = $maybe_version_token->[1];
2271 29 100 66     179 if ($maybe_version_token_desc and ($maybe_version_token_desc eq 'NUMBER' or $maybe_version_token_desc eq 'VERSION_STRING')) {
      66        
2272 3         15 $c->add_no($name => $maybe_version_token->[0]);
2273 3         376 shift @$tokens;
2274             } else {
2275 26         112 $c->add_no($name => 0);
2276             }
2277             }
2278              
2279 29 100       1051 if ($c->has_callback_for(no => $name)) {
2280 2         4 eval { $c->run_callback_for(no => $name, $tokens) };
  2         7  
2281 2 50       6 warn "Callback Error: $@" if $@;
2282 2         6 return;
2283             }
2284             }
2285              
2286             1;
2287              
2288             __END__