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   4913941 use strict;
  88         897  
  88         2154  
4 88     88   355 use warnings;
  88         133  
  88         1558  
5 88     88   338 use Carp;
  88         130  
  88         3810  
6 88     88   35366 use Perl::PrereqScanner::NotQuiteLite::Context;
  88         271  
  88         3249  
7 88     88   961 use Perl::PrereqScanner::NotQuiteLite::Util;
  88         161  
  88         12270  
8              
9             our $VERSION = '0.9916';
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   566 use constant DEBUG => !!$ENV{PERL_PSNQL_DEBUG} || 0;
  88         194  
  88         5649  
23 88     88   474 use constant DEBUG_RE => DEBUG > 3 ? 1 : 0;
  88         148  
  88         7926  
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   1247 no warnings 'redefine';
  88         163  
  88         1315178  
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         14 $@ = shift() . substr($$rstr, pos($$rstr), 100);
44 5         21 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   513 my $delim = shift;
110 297   66     1138 $ReStrInDelims{$delim} ||= do {
111 296 100       697 if ($delim eq '\\') {
112 2         9 qr/(?:[^\\]*(?:(?:\\\\)[^\\]*)*)/s;
113             } else {
114 294         558 $delim = quotemeta $delim;
115 294         4960 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   176 my $delim = shift;
127 96   66     382 $ReStrInDelimsWithEndDelim{$delim} ||= do {
128 33         158 my $re = _gen_re_str_in_delims($delim);
129 33         736 qr{$re\Q$delim\E};
130             };
131             }
132              
133             my %RdelSkip;
134             sub _gen_rdel_and_re_skip {
135 158     158   269 my $ldel = shift;
136 158   66     218 @{$RdelSkip{$ldel} ||= do {
  158         712  
137 37         116 (my $rdel = $ldel) =~ tr/[({/;
138 37         565 my $re_skip = qr{[^\Q$ldel$rdel\E\\]+};
139 37         233 [$rdel, $re_skip];
140             }};
141             }
142              
143             my %RegexpShortcut;
144             sub _gen_re_regexp_shortcut {
145 198     198   365 my ($ldel, $rdel) = @_;
146 198   66     641 $RegexpShortcut{$ldel} ||= do {
147 28         62 $ldel = quotemeta $ldel;
148 28 100       82 $rdel = $rdel ? quotemeta $rdel : $ldel;
149 28         1099 qr{(?:[^\\\(\)\{\}\[\]<>$ldel$rdel]*(?:\\.[^\\\(\)\[\]\{\}<>$ldel$rdel]*)*)$rdel};
150             };
151             }
152              
153             ############################
154              
155             my %LOADED;
156              
157             sub new {
158 697     697 1 1695345 my ($class, %args) = @_;
159              
160 697         1327 my %mapping;
161 697         2730 my @parsers = $class->_get_parsers($args{parsers});
162 697         1446 for my $parser (@parsers) {
163 20772 100       37701 if (!exists $LOADED{$parser}) {
164 2433         113959 eval "require $parser; 1";
165 2433 50       9731 if (my $error = $@) {
166 0 0       0 $parser->can('register') or die "Parser Error: $error";
167             }
168 2433 50       29322 $LOADED{$parser} = $parser->can('register') ? $parser->register(%args) : undef;
169             }
170 20772 50       36623 my $parser_mapping = $LOADED{$parser} or next;
171 20772         26337 for my $type (qw/use no keyword method/) {
172 83088 100       122824 next unless exists $parser_mapping->{$type};
173 22857         23898 for my $name (keys %{$parser_mapping->{$type}}) {
  22857         50865  
174             $mapping{$type}{$name} = [
175             $parser,
176 120269 100 100     319373 $parser_mapping->{$type}{$name},
177             (($type eq 'use' or $type eq 'no') ? ($name) : ()),
178             ];
179             }
180             }
181 20772 100       82243 if ($parser->can('register_fqfn')) {
182 2079         6466 my $fqfn_mapping = $parser->register_fqfn;
183 2079         4971 for my $name (keys %$fqfn_mapping) {
184 6234         18500 my ($module) = $name =~ /^(.+)::/;
185             $mapping{keyword}{$name} = [
186             $parser,
187 6234         16540 $fqfn_mapping->{$name},
188             $module,
189             ];
190             }
191             }
192             }
193 697         1556 $args{_} = \%mapping;
194              
195 697         3265 bless \%args, $class;
196             }
197              
198             sub _get_parsers {
199 697     697   1459 my ($class, $list) = @_;
200 697         1255 my @parsers;
201             my %should_ignore;
202 697 50       1114 for my $parser (@{$list || [qw/:default/]}) {
  697         2372  
203 701 50       2550 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 692         1959 push @parsers, map {"$class\::Parser::$_"} @BUNDLED_PARSERS;
  20760         36192  
208             } elsif ($parser eq ':default') {
209 5         14 push @parsers, map {"$class\::Parser::$_"} @DEFAULT_PARSERS;
  10         31  
210             } elsif ($parser =~ s/^\+//) {
211 1         3 push @parsers, $parser;
212             } elsif ($parser =~ s/^\-//) {
213 1         4 $should_ignore{"$class\::Parser\::$parser"} = 1;
214             } elsif ($parser =~ /^$class\::Parser::/) {
215 1         3 push @parsers, $parser;
216             } else {
217 1         4 push @parsers, "$class\::Parser\::$parser";
218             }
219             }
220 697         1483 grep {!$should_ignore{$_}} @parsers;
  20773         27927  
221             }
222              
223             sub scan_file {
224 72     72 1 180 my ($self, $file) = @_;
225 72         93 _debug("START SCANNING $file") if DEBUG;
226 72 50       232 print STDERR " Scanning $file\n" if $self->{verbose};
227 72 50       2353 open my $fh, '<', $file or croak "Can't open $file: $!";
228 72         187 my $code = do { local $/; <$fh> };
  72         308  
  72         1770  
229 72         265 $self->{file} = $file;
230 72         233 $self->scan_string($code);
231             }
232              
233             sub scan_string {
234 697     697 1 3396 my ($self, $string) = @_;
235              
236 697 50       1623 $string = '' unless defined $string;
237              
238 697         3910 my $c = Perl::PrereqScanner::NotQuiteLite::Context->new(%$self);
239              
240 697 50       2244 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 697 50       2477 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 697         1834 $string =~ s/\A(\x00\x00\xfe\xff|\xff\xfe\x00\x00|\xfe\xff|\xff\xfe)//s;
252              
253             # normalize
254 697         1004 if ("\n" eq "\015") {
255             $string =~ s/(?:\015?\012)/\n/gs;
256             } elsif ("\n" eq "\012") {
257 697         1468 $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 697         9495 $string =~ s/[ \t]+/ /g;
264 697         9798 $string =~ s/(?: *\n)+/\n/gs;
265              
266             # FIXME
267 697         2008 $c->{stack} = [];
268 697         1353 $c->{errors} = [];
269             $c->{callback} = {
270 697         3019 use => \&_use,
271             require => \&_require,
272             no => \&_no,
273             };
274 697         1590 $c->{wants_doc} = 0;
275              
276 697         2011 pos($string) = 0;
277              
278             {
279 697         1313 local $@;
  706         1076  
280 706         1240 eval { $self->_scan($c, \$string, 0) };
  706         2372  
281 706 50       1588 push @{$c->{errors}}, "Scan Error: $@" if $@;
  0         0  
282 706 100       1958 if ($c->{redo}) {
283 9         16 delete $c->{redo};
284 9         15 delete $c->{ended};
285 9         15 @{$c->{stack}} = ();
  9         18  
286 9         16 redo;
287             }
288             }
289              
290 697 100 66     1040 if (@{$c->{stack}} and !$c->{quick}) {
  697         2186  
291 1         455 require Data::Dump;
292 1         3833 push @{$c->{errors}}, Data::Dump::dump($c->{stack});
  1         7  
293             }
294              
295 697         16736 $c->remove_inner_packages_from_requirements;
296 697         2525 $c->merge_perl;
297              
298 697         7980 $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 3089     3089   5827 my ($self, $c, $rstr, $parent_scope) = @_;
320              
321 3089 100       3595 if (@{$c->{stack}} > 90) {
  3089         6592  
322 1         4 _error("deep recursion found");
323 1         3 $c->{ended} = 1;
324             }
325              
326 3089         3909 _dump_stack($c, "BEGIN SCOPE") if DEBUG;
327              
328             # found __DATA|END__ somewhere?
329 3089 100       5221 return $c if $c->{ended};
330              
331 3088         4603 my $wants_doc = $c->{wants_doc};
332 3088         3729 my $line_top = 1;
333 3088         3481 my $waiting_for_a_block;
334              
335 3088         3545 my $current_scope = 0;
336 3088         5503 my ($token, $token_desc, $token_type) = ('', '', '');
337 3088         4429 my ($prev_token, $prev_token_type) = ('', '');
338 3088         11166 my ($stack, $unstack);
339 3088         0 my (@keywords, @tokens, @scope_tokens);
340 3088         0 my $caller_package;
341 3088         0 my $prepend;
342 3088         0 my ($pos, $c1);
343 3088         3670 my $prev_pos = 0;
344 3088         5740 while(defined($pos = pos($$rstr))) {
345 46331         52513 $token = undef;
346              
347             # cache first letter for better performance
348 46331         60973 $c1 = substr($$rstr, $pos, 1);
349              
350 46331 100       62068 if ($line_top) {
351 7471 100       11365 if ($c1 eq '=') {
352 10 50       406 if ($$rstr =~ m/\G($re_pod)/gcsx) {
353 10 50       26 ($token, $token_desc, $token_type) = ($1, 'POD', '') if $wants_doc;
354 10         20 next;
355             }
356             }
357             }
358 46321 100       63268 if ($c1 eq "\n") {
359 4116         7404 pos($$rstr)++;
360 4116         5737 $line_top = 1;
361 4116         5020 next;
362             }
363              
364 42205         44489 $line_top = 0;
365             # ignore whitespaces
366 42205 100       195731 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 14663         23768 pos($$rstr)++;
368 14663         20838 next;
369             } elsif ($c1 eq '_') {
370 57         145 my $c2 = substr($$rstr, $pos + 1, 1);
371 57 100 100     241 if ($c2 eq '_' and $$rstr =~ m/\G(__(?:DATA|END)__\b)(?!\s*=>)/gc) {
372 1 50       5 if ($wants_doc) {
373 0         0 ($token, $token_desc, $token_type) = ($1, 'END_OF_CODE', '');
374 0         0 next;
375             } else {
376 1         2 $c->{ended} = 1;
377 1         2 last;
378             }
379             }
380             } elsif ($c1 eq '#') {
381 257 50       3627 if ($$rstr =~ m{\G($re_comment)}gcs) {
382 257 50       583 ($token, $token_desc, $token_type) = ($1, 'COMMENT', '') if $wants_doc;
383 257         370 $line_top = 1;
384 257         377 next;
385             }
386             } elsif ($c1 eq ';') {
387 2590         4969 pos($$rstr) = $pos + 1;
388 2590         5139 ($token, $token_desc, $token_type) = ($c1, ';', ';');
389 2590         3228 $current_scope |= F_STATEMENT_END|F_EXPR_END;
390 2590         3153 next;
391             } elsif ($c1 eq '$') {
392 3668         5278 my $c2 = substr($$rstr, $pos + 1, 1);
393 3668 100 66     29207 if ($c2 eq '#') {
    100 100        
    100          
    100          
    100          
    100          
394 32 100       495 if (substr($$rstr, $pos + 2, 1) eq '{') {
    100          
    100          
395 2 50       11 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         7 pos($$rstr) = $pos + 3;
400 2         16 ($token, $token_desc, $token_type) = ('$#{', '$#{', 'EXPR');
401 2         7 $stack = [$token, $pos, 'VARIABLE'];
402 2         4 next;
403             }
404             } elsif ($$rstr =~ m{\G(\$\#(?:$re_namespace))}gc) {
405 14         50 ($token, $token_desc, $token_type) = ($1, '$#NAME', 'EXPR');
406 14         27 next;
407             } elsif ($prev_token_type eq 'ARROW') {
408 2         9 my $c3 = substr($$rstr, $pos + 2, 1);
409 2 50       6 if ($c3 eq '*') {
410 2         7 pos($$rstr) = $pos + 3;
411 2         5 ($token, $token_desc, $token_type) = ('$#*', 'VARIABLE', 'VARIABLE');
412 2         9 $c->add_perl('5.020', '->$#*');
413 2         5 next;
414             }
415             } else {
416 14         87 pos($$rstr) = $pos + 2;
417 14         35 ($token, $token_desc, $token_type) = ('$#', 'SPECIAL_VARIABLE', 'EXPR');
418 14         24 next;
419             }
420             } elsif ($c2 eq '$') {
421 44 100       419 if ($$rstr =~ m{\G(\$(?:\$)+(?:$re_namespace))}gc) {
422 42         112 ($token, $token_desc, $token_type) = ($1, '$$NAME', 'VARIABLE');
423 42         78 next;
424             } else {
425 2         6 pos($$rstr) = $pos + 2;
426 2         6 ($token, $token_desc, $token_type) = ('$$', 'SPECIAL_VARIABLE', 'EXPR');
427 2         4 next;
428             }
429             } elsif ($c2 eq '{') {
430 10 100       55 if ($$rstr =~ m{\G(\$\{[\w\s]+\})}gc) {
    50          
431 2         6 ($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         22 pos($$rstr) = $pos + 2;
446 8         19 ($token, $token_desc, $token_type) = ('${', '${', 'VARIABLE');
447 8         19 $stack = [$token, $pos, 'VARIABLE'];
448             }
449 10 100       30 if ($parent_scope & F_EXPECTS_BRACKET) {
450 3         4 $current_scope |= F_SCOPE_END;
451             }
452 10         16 next;
453             } elsif ($c2 eq '*' and $prev_token_type eq 'ARROW') {
454 2         5 pos($$rstr) = $pos + 2;
455 2         6 ($token, $token_desc, $token_type) = ('$*', '$*', 'VARIABLE');
456 2         17 $c->add_perl('5.020', '->$*');
457 2         5 next;
458             } elsif ($c2 eq '+' or $c2 eq '-') {
459 2         5 pos($$rstr) = $pos + 2;
460 2         7 ($token, $token_desc, $token_type) = ('$'.$c2, 'SPECIAL_VARIABLE', 'VARIABLE');
461 2         7 $c->add_perl('5.010', '$'.$c2);
462 2         4 next;
463             } elsif ($$rstr =~ m{$g_re_scalar_variable}gc) {
464 3576         8534 ($token, $token_desc, $token_type) = ($1, '$NAME', 'VARIABLE');
465 3576         4642 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         683 my $c2 = substr($$rstr, $pos + 1, 1);
473 317 100 100     2848 if ($c2 eq '_' and $$rstr =~ m{\G\@_\b}gc) {
    100 100        
    100          
    100          
    100          
    100          
    50          
474 118         618 ($token, $token_desc, $token_type) = ('@_', 'SPECIAL_VARIABLE', 'VARIABLE');
475 118         181 next;
476             } elsif ($c2 eq '{') {
477 37 50       225 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         144 ($token, $token_desc, $token_type) = ($1, '@{^NAME}', 'VARIABLE');
484 2 50 33     9 if ($token eq '@{^CAPTURE}' or $token eq '@{^CAPTURE_ALL}') {
485 2         42 $c->add_perl('5.026', '@{^CAPTURE}');
486             }
487             } else {
488 35         94 pos($$rstr) = $pos + 2;
489 35         98 ($token, $token_desc, $token_type) = ('@{', '@{', 'VARIABLE');
490 35         203 $stack = [$token, $pos, 'VARIABLE'];
491             }
492 37 100       105 if ($prev_token_type eq 'ARROW') {
493 5         14 $c->add_perl('5.020', '->@{}');
494             }
495 37 50       109 if ($parent_scope & F_EXPECTS_BRACKET) {
496 0         0 $current_scope |= F_SCOPE_END;
497             }
498 37         123 next;
499             } elsif ($c2 eq '$') {
500 37 100       463 if ($$rstr =~ m{\G(\@\$(?:$re_namespace))}gc) {
501 35         98 ($token, $token_desc, $token_type) = ($1, '@$NAME', 'VARIABLE');
502 35         66 next;
503             } else {
504 2         7 pos($$rstr) = $pos + 2;
505 2         6 ($token, $token_desc, $token_type) = ('@$', '@$', 'VARIABLE');
506 2         3 next;
507             }
508             } elsif ($prev_token_type eq 'ARROW') {
509             # postderef
510 11 100       24 if ($c2 eq '*') {
511 5         13 pos($$rstr) = $pos + 2;
512 5         13 ($token, $token_desc, $token_type) = ('@*', '@*', 'VARIABLE');
513 5         18 $c->add_perl('5.020', '->@*');
514 5         7 next;
515             } else {
516 6         13 pos($$rstr) = $pos + 1;
517 6         16 ($token, $token_desc, $token_type) = ('@', '@', 'VARIABLE');
518 6         21 $c->add_perl('5.020', '->@');
519 6         11 next;
520             }
521             } elsif ($c2 eq '[') {
522 1         3 pos($$rstr) = $pos + 2;
523 1         4 ($token, $token_desc, $token_type) = ('@[', 'SPECIAL_VARIABLE', 'VARIABLE');
524 1         2 next;
525             } elsif ($c2 eq '+' or $c2 eq '-') {
526 2         6 pos($$rstr) = $pos + 2;
527 2         7 ($token, $token_desc, $token_type) = ('@'.$c2, 'SPECIAL_VARIABLE', 'VARIABLE');
528 2         8 $c->add_perl('5.010', '@'.$c2);
529 2         4 next;
530             } elsif ($$rstr =~ m{\G(\@(?:$re_namespace))}gc) {
531 111         316 ($token, $token_desc, $token_type) = ($1, '@NAME', 'VARIABLE');
532 111         178 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         288 my $c2 = substr($$rstr, $pos + 1, 1);
540 117 100 66     2124 if ($c2 eq '{') {
    100 66        
    100          
    100          
    100          
    100          
    50          
541 42 50       312 if ($$rstr =~ m{\G(\%\{[\w\s]+\})}gc) {
    100          
542 0         0 ($token, $token_desc, $token_type) = ($1, '%{NAME}', 'VARIABLE');
543             } elsif ($$rstr =~ m{\G(\%\{\^[A-Z_]+\})}gc) {
544 2         7 ($token, $token_desc, $token_type) = ($1, '%{^NAME}', 'VARIABLE');
545 2 50 66     10 if ($token eq '%{^CAPTURE}' or $token eq '%{^CAPTURE_ALL}') {
546 2         5 $c->add_perl('5.026', '%{^CAPTURE}');
547             }
548             } else {
549 40         111 pos($$rstr) = $pos + 2;
550 40         114 ($token, $token_desc, $token_type) = ('%{', '%{', 'VARIABLE');
551 40         109 $stack = [$token, $pos, 'VARIABLE'];
552             }
553 42 100       116 if ($prev_token_type eq 'ARROW') {
554 4         13 $c->add_perl('5.020', '->%{');
555             }
556 42 50       103 if ($parent_scope & F_EXPECTS_BRACKET) {
557 0         0 $current_scope |= F_SCOPE_END;
558             }
559 42         61 next;
560             } elsif ($c2 eq '=') {
561 1         3 pos($$rstr) = $pos + 2;
562 1         2 ($token, $token_desc, $token_type) = ('%=', '%=', 'OP');
563 1         3 next;
564             } elsif ($$rstr =~ m{\G(\%\$(?:$re_namespace))}gc) {
565 5         18 ($token, $token_desc, $token_type) = ($1, '%$NAME', 'VARIABLE');
566 5         10 next;
567             } elsif ($$rstr =~ m{\G(\%(?:$re_namespace))}gc) {
568 57         203 ($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         11 pos($$rstr) = $pos + 1;
572 4         19 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
573 4         8 next;
574             } elsif ($prev_token_type eq 'ARROW') {
575 6 100       18 if ($c2 eq '*') {
576 2         7 pos($$rstr) = $pos + 2;
577 2         6 ($token, $token_desc, $token_type) = ('%*', '%*', 'VARIABLE');
578 2         8 $c->add_perl('5.020', '->%*');
579 2         4 next;
580             } else {
581 4         10 pos($$rstr) = $pos + 1;
582 4         11 ($token, $token_desc, $token_type) = ('%', '%', 'VARIABLE');
583 4         15 $c->add_perl('5.020', '->%');
584 4         8 next;
585             }
586             } elsif ($c2 eq '+' or $c2 eq '-') {
587 2         8 pos($$rstr) = $pos + 2;
588 2         8 ($token, $token_desc, $token_type) = ('%'.$c2, 'SPECIAL_VARIABLE', 'VARIABLE');
589 2         8 $c->add_perl('5.010', '%'.$c2);
590 2         4 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         206 my $c2 = substr($$rstr, $pos + 1, 1);
598 89 100       800 if ($c2 eq '{') {
    100          
    100          
    100          
599 15 100       88 if ($prev_token_type eq 'ARROW') {
    50          
600 2         7 pos($$rstr) = $pos + 2;
601 2         8 ($token, $token_desc, $token_type) = ('*{', '*{', 'VARIABLE');
602 2         8 $c->add_perl('5.020', '->*{}');
603 2         5 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         46 pos($$rstr) = $pos + 2;
612 13         41 ($token, $token_desc, $token_type) = ('*{', '*{', 'VARIABLE');
613 13         32 $stack = [$token, $pos, 'VARIABLE'];
614             }
615 13 50       37 if ($parent_scope & F_EXPECTS_BRACKET) {
616 0         0 $current_scope |= F_SCOPE_END;
617             }
618 13         24 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         5 pos($$rstr) = $pos + 2;
626 2         5 ($token, $token_desc, $token_type) = ('**', '**', 'VARIABLE');
627 2         7 $c->add_perl('5.020', '->**');
628 2         3 next;
629             } else {
630 1         3 pos($$rstr) = $pos + 2;
631 1         3 ($token, $token_desc, $token_type) = ('**', '**', 'OP');
632 1         2 next;
633             }
634             } elsif ($c2 eq '=') {
635 2         6 pos($$rstr) = $pos + 2;
636 2         6 ($token, $token_desc, $token_type) = ('*=', '*=', 'OP');
637 2         5 next;
638             } elsif ($$rstr =~ m{\G(\*(?:$re_namespace))}gc) {
639 29         93 ($token, $token_desc, $token_type) = ($1, '*NAME', 'VARIABLE');
640 29         47 next;
641             } else {
642 40         93 pos($$rstr) = $pos + 1;
643 40         87 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
644 40         134 next;
645             }
646             } elsif ($c1 eq '&') {
647 129         251 my $c2 = substr($$rstr, $pos + 1, 1);
648 129 100       1158 if ($c2 eq '&') {
    50          
    100          
    100          
    100          
    100          
    100          
649 58         112 pos($$rstr) = $pos + 2;
650 58         119 ($token, $token_desc, $token_type) = ('&&', '&&', 'OP');
651 58         78 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       196 if ($$rstr =~ m{\G(\&\{[\w\s]+\})}gc) {
658 0         0 ($token, $token_desc, $token_type) = ($1, '&{NAME}', 'EXPR');
659             } else {
660 8         23 pos($$rstr) = $pos + 2;
661 8         27 ($token, $token_desc, $token_type) = ('&{', '&{', 'EXPR');
662 8         83 $stack = [$token, $pos, 'FUNC'];
663             }
664 8 50       77 if ($parent_scope & F_EXPECTS_BRACKET) {
665 0         0 $current_scope |= F_SCOPE_END;
666             }
667 8         18 next;
668             } elsif ($c2 eq '.') {
669 2 100       22 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         4 ($token, $token_desc, $token_type) = ('&.', '&.', 'OP');
675             }
676 2         7 $c->add_perl('5.022', '&.');
677 2         3 next;
678             } elsif ($$rstr =~ m{\G(\&(?:$re_namespace))}gc) {
679 48         125 ($token, $token_desc, $token_type) = ($1, '&NAME', 'EXPR');
680 48         81 next;
681             } elsif ($$rstr =~ m{\G(\&\$(?:$re_namespace))}gc) {
682 3         12 ($token, $token_desc, $token_type) = ($1, '&$NAME', 'EXPR');
683 3         8 next;
684             } elsif ($prev_token_type eq 'ARROW') {
685 2 50       8 if ($c2 eq '*') {
686 2         6 pos($$rstr) = $pos + 2;
687 2         12 ($token, $token_desc, $token_type) = ('&*', '&*', 'VARIABLE');
688 2         10 $c->add_perl('5.020', '->&*');
689 2         4 next;
690             }
691             } else {
692 8         23 pos($$rstr) = $pos + 1;
693 8         24 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
694 8         13 next;
695             }
696             } elsif ($c1 eq '\\') {
697 70         156 my $c2 = substr($$rstr, $pos + 1, 1);
698 70 50       146 if ($c2 eq '{') {
699 0 0       0 if ($$rstr =~ m{\G(\\\{[\w\s]+\})}gc) {
700 0         0 ($token, $token_desc, $token_type) = ($1, '\\{NAME}', 'VARIABLE');
701             } else {
702 0         0 pos($$rstr) = $pos + 2;
703 0         0 ($token, $token_desc, $token_type) = ('\\{', '\\{', 'VARIABLE');
704 0         0 $stack = [$token, $pos, 'VARIABLE'];
705             }
706 0 0       0 if ($parent_scope & F_EXPECTS_BRACKET) {
707 0         0 $current_scope |= F_SCOPE_END;
708             }
709 0         0 next;
710             } else {
711 70         147 pos($$rstr) = $pos + 1;
712 70         151 ($token, $token_desc, $token_type) = ($c1, $c1, '');
713 70         96 next;
714             }
715             } elsif ($c1 eq '-') {
716 1267         2213 my $c2 = substr($$rstr, $pos + 1, 1);
717 1267 100       2915 if ($c2 eq '>') {
    100          
    100          
    100          
718 1103         1999 pos($$rstr) = $pos + 2;
719 1103         2549 ($token, $token_desc, $token_type) = ('->', 'ARROW', 'ARROW');
720 1103 100 100     3112 if ($prev_token_type eq 'WORD' or $prev_token_type eq 'KEYWORD') {
721 51         204 $caller_package = $prev_token;
722 51         102 $current_scope |= F_KEEP_TOKENS;
723             }
724 1103         1511 next;
725             } elsif ($c2 eq '-') {
726 4         15 pos($$rstr) = $pos + 2;
727 4         12 ($token, $token_desc, $token_type) = ('--', '--', $prev_token_type);
728 4         9 next;
729             } elsif ($c2 eq '=') {
730 5         14 pos($$rstr) = $pos + 2;
731 5         12 ($token, $token_desc, $token_type) = ('-=', '-=', 'OP');
732 5         10 next;
733             } elsif ($$rstr =~ m{\G(\-[ABCMORSTWXbcdefgkloprstuwxz]\b)}gc) {
734 4         19 ($token, $token_desc, $token_type) = ($1, 'FILE_TEST', 'EXPR');
735 4         11 next;
736             } else {
737 151         325 pos($$rstr) = $pos + 1;
738 151         333 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
739 151         201 next;
740             }
741             } elsif ($c1 eq q{"}) {
742 436 100       3605 if ($$rstr =~ m{\G(?:\"($re_str_in_double_quotes)\")}gcs) {
743 435         1597 ($token, $token_desc, $token_type) = ([$1, q{"}], 'STRING', 'STRING');
744 435         710 next;
745             }
746             } elsif ($c1 eq q{'}) {
747 859 50       6690 if ($$rstr =~ m{\G(?:\'($re_str_in_single_quotes)\')}gcs) {
748 859         3087 ($token, $token_desc, $token_type) = ([$1, q{'}], 'STRING', 'STRING');
749 859         1412 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     625 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       265 if (my $regexp = $self->_match_regexp0($c, $rstr, $pos, 'm')) {
759 96         196 ($token, $token_desc, $token_type) = ($regexp, 'REGEXP', 'EXPR');
760 96         158 next;
761             } else {
762             # the above may fail
763 1         1 _debug("REGEXP ERROR: $@") if DEBUG;
764 1         3 pos($$rstr) = $pos;
765             }
766             }
767 48 50 33     295 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       4 if (my $regexp = $self->_match_regexp0($c, $rstr, $pos)) {
770 0         0 ($token, $token_desc, $token_type) = ($regexp, 'REGEXP', 'EXPR');
771 0         0 next;
772             } else {
773             # the above may fail
774 1         2 _debug("REGEXP ERROR: $@") if DEBUG;
775 1         2 pos($$rstr) = $pos;
776             }
777             }
778 48         98 my $c2 = substr($$rstr, $pos + 1, 1);
779 48 100       101 if ($c2 eq '/') {
780 9 100       28 if (substr($$rstr, $pos + 2, 1) eq '=') {
781 2         6 pos($$rstr) = $pos + 3;
782 2         7 ($token, $token_desc, $token_type) = ('//=', '//=', 'OP');
783 2         10 $c->add_perl('5.010', '//=');
784 2         4 next;
785             } else {
786 7         13 pos($$rstr) = $pos + 2;
787 7         25 ($token, $token_desc, $token_type) = ('//', '//', 'OP');
788 7         22 $c->add_perl('5.010', '//');
789 7         10 next;
790             }
791             }
792 39 100       72 if ($c2 eq '=') { # this may be a part of /=.../
793 1         3 pos($$rstr) = $pos + 2;
794 1         3 ($token, $token_desc, $token_type) = ('/=', '/=', 'OP');
795 1         2 next;
796             } else {
797 38         72 pos($$rstr) = $pos + 1;
798 38         95 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
799 38         50 next;
800             }
801             } elsif ($c1 eq '{') {
802 1785 100       11809 if ($$rstr =~ m{$g_re_hash_shortcut}gc) {
803 879         2338 ($token, $token_desc) = ($1, '{EXPR}');
804 879 100       1605 if ($current_scope & F_EVAL) {
805 1         1 $current_scope &= MASK_EVAL;
806 1 50       4 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
807             }
808 879 100       1539 if ($parent_scope & F_EXPECTS_BRACKET) {
809 8         12 $current_scope |= F_SCOPE_END;
810 8         12 next;
811             }
812 871 100 100     2250 if ($prev_token_type eq 'ARROW' or $prev_token_type eq 'VARIABLE') {
    100 100        
    100          
813 755         950 $token_type = 'VARIABLE';
814 755         939 next;
815             } elsif ($waiting_for_a_block) {
816 82         115 $waiting_for_a_block = 0;
817 82 100 100     338 if (@keywords and $c->token_expects_block($keywords[0])) {
818 70         207 my $first_token = $keywords[0];
819 70         106 $current_scope |= F_EXPR_END;
820 70 100 100     237 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         5 $current_scope &= MASK_KEEP_TOKENS;
823 3         10 @tokens = ();
824             }
825             }
826 82         131 next;
827             } elsif ($prev_token_type eq 'KEYWORD' and $c->token_expects_fh_or_block_list($prev_token)) {
828 15         20 $token_type = '';
829 15         16 next;
830             } else {
831 19         34 $token_type = 'EXPR';
832 19         31 next;
833             }
834             }
835 906         2146 pos($$rstr) = $pos + 1;
836 906         1928 ($token, $token_desc) = ($c1, $c1);
837 906         1134 my $stack_owner;
838 906 100       1754 if (@keywords) {
839 713         1656 for(my $i = @keywords; $i > 0; $i--) {
840 745         1349 my $keyword = $keywords[$i - 1];
841 745 100       1653 if ($c->token_expects_block($keyword)) {
842 672         985 $stack_owner = $keyword;
843 672 100 100     1587 if (@tokens and $c->token_defines_sub($keyword) and $c->has_callback_for(sub => $keyword)) {
      100        
844 40         172 $c->run_callback_for(sub => $keyword, \@tokens);
845 40         583 $current_scope &= MASK_KEEP_TOKENS;
846 40         117 @tokens = ();
847             }
848 672         1098 last;
849             }
850             }
851             }
852 906   100     2638 $stack = [$token, $pos, $stack_owner || ''];
853 906 100       1861 if ($parent_scope & F_EXPECTS_BRACKET) {
854 62         77 $current_scope |= F_SCOPE_END|F_STATEMENT_END|F_EXPR_END;
855 62         101 next;
856             }
857 844 100 100     3211 if ($prev_token_type eq 'ARROW' or $prev_token_type eq 'VARIABLE') {
    100          
858 35         63 $token_type = 'VARIABLE';
859             } elsif ($waiting_for_a_block) {
860 676         950 $waiting_for_a_block = 0;
861             } else {
862 133 100       375 $token_type = (($current_scope | $parent_scope) & F_KEEP_TOKENS) ? 'EXPR' : '';
863             }
864 844         1133 next;
865             } elsif ($c1 eq '[') {
866 395 100       2870 if ($$rstr =~ m{\G(\[(?:$re_nonblock_chars)\])}gc) {
867 208         519 ($token, $token_desc, $token_type) = ($1, '[EXPR]', 'VARIABLE');
868 208         352 next;
869             } else {
870 187         488 pos($$rstr) = $pos + 1;
871 187         440 ($token, $token_desc, $token_type) = ($c1, $c1, 'VARIABLE');
872 187         378 $stack = [$token, $pos, 'VARIABLE'];
873 187         322 next;
874             }
875             } elsif ($c1 eq '(') {
876 1486         3534 my $prototype_re = $c->prototype_re;
877 1486 100 100     10648 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         264 my $proto = $1;
879 101 100       424 if ($proto =~ /^\([\\\$\@\%\&\[\]\*;\+]*\)$/) {
880 56         119 ($token, $token_desc, $token_type) = ($proto, '(PROTOTYPE)', '');
881             } else {
882 45         104 ($token, $token_desc, $token_type) = ($proto, '(SIGNATURES)', '');
883 45         128 $c->add_perl('5.020', 'signatures');
884             }
885 101         165 next;
886             } elsif ($$rstr =~ m{\G\(((?:$re_nonblock_chars)(?
887 295         1481 ($token, $token_desc, $token_type) = ([[[$1, 'EXPR']]], '()', 'EXPR');
888 295 100 100     1295 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       135 if ($prev_token eq 'eval') {
890 1         2 $current_scope &= MASK_EVAL;
891 1 50       4 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
892             }
893 54         128 pop @keywords;
894             }
895 295         566 next;
896             } else {
897 1090         2742 pos($$rstr) = $pos + 1;
898 1090         2369 ($token, $token_desc, $token_type) = ($c1, $c1, 'EXPR');
899 1090         1318 my $stack_owner;
900 1090 100       2085 if (@keywords) {
901 609         1425 for (my $i = @keywords; $i > 0; $i--) {
902 661         1199 my $keyword = $keywords[$i - 1];
903 661 100       1412 if ($c->token_expects_block($keyword)) {
904 215         352 $stack_owner = $keyword;
905 215         347 last;
906             }
907             }
908             }
909 1090   100     3601 $stack = [$token, $pos, $stack_owner || ''];
910 1090         1874 next;
911             }
912             } elsif ($c1 eq '}') {
913 1009         2004 pos($$rstr) = $pos + 1;
914 1009         2008 ($token, $token_desc, $token_type) = ($c1, $c1, '');
915 1009         1282 $unstack = $token;
916 1009         1627 $current_scope |= F_STATEMENT_END|F_EXPR_END;
917 1009         1384 next;
918             } elsif ($c1 eq ']') {
919 96         234 pos($$rstr) = $pos + 1;
920 96         220 ($token, $token_desc, $token_type) = ($c1, $c1, '');
921 96         194 $unstack = $token;
922 96         140 next;
923             } elsif ($c1 eq ')') {
924 1090         2233 pos($$rstr) = $pos + 1;
925 1090         2175 ($token, $token_desc, $token_type) = ($c1, $c1, '');
926 1090         1386 $unstack = $token;
927 1090         1379 next;
928             } elsif ($c1 eq '<') {
929 93         200 my $c2 = substr($$rstr, $pos + 1, 1);
930 93 100       577 if ($c2 eq '<'){
    100          
    100          
    100          
931 19 100       162 if ($$rstr =~ m{\G(<<(?:
    100          
932             \\. |
933             \w+ |
934             [./-] |
935             \[[^\]]*\] |
936             \{[^\}]*\} |
937             \* |
938             \? |
939             \~ |
940             \$ |
941             )*(?>)}gcx) {
942 1         4 ($token, $token_desc, $token_type) = ($1, '<>', 'EXPR');
943 1         4 $c->add_perl('5.022', '<>');
944 1         3 next;
945             } elsif ($$rstr =~ m{\G<<~?\s*(?:
946             \\?[A-Za-z_][\w]* |
947             "(?:[^\\"]*(?:\\.[^\\"]*)*)" |
948             '(?:[^\\']*(?:\\.[^\\']*)*)' |
949             `(?:[^\\`]*(?:\\.[^\\`]*)*)`
950             )}sx) {
951 16 100       64 if (my $heredoc = $self->_match_heredoc($c, $rstr)) {
952 14         40 ($token, $token_desc, $token_type) = ($heredoc, 'HEREDOC', 'EXPR');
953 14         27 next;
954             } else {
955             # the above may fail
956 2         4 pos($$rstr) = $pos;
957             }
958             }
959 4 50       16 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         8 ($token, $token_desc, $token_type) = ('<<', '<<', 'OP');
966 4         7 next;
967             }
968             } elsif ($c2 eq '=') {
969 10 100       37 if (substr($$rstr, $pos + 2, 1) eq '>') {
970 1         5 pos($$rstr) = $pos + 3;
971 1         4 ($token, $token_desc, $token_type) = ('<=>', '<=>', 'OP');
972 1         4 next;
973             } else {
974 9         21 pos($$rstr) = $pos + 2;
975 9         26 ($token, $token_desc, $token_type) = ('<=', '<=', 'OP');
976 9         12 next;
977             }
978             } elsif ($c2 eq '>') {
979 1         3 pos($$rstr) = $pos + 2;
980 1         4 ($token, $token_desc, $token_type) = ('<>', '<>', 'OP');
981 1         2 next;
982             } elsif ($$rstr =~ m{\G(<(?:
983             \\. |
984             \w+ |
985             [./-] |
986             \[[^\]]*\] |
987             \{[^\}]*\} |
988             \* |
989             \? |
990             \~ |
991             \$ |
992             )*(?)}gcx) {
993 12         45 ($token, $token_desc, $token_type) = ($1, '', 'EXPR');
994 12         21 next;
995             } else {
996 51         117 pos($$rstr) = $pos + 1;
997 51         113 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
998 51         81 next;
999             }
1000             } elsif ($c1 eq ':') {
1001 227         498 my $c2 = substr($$rstr, $pos + 1, 1);
1002 227 100       505 if ($c2 eq ':') {
1003 21         53 pos($$rstr) = $pos + 2;
1004 21         53 ($token, $token_desc, $token_type) = ('::', '::', '');
1005 21         30 next;
1006             }
1007 206 100 100     746 if ($waiting_for_a_block and @keywords and $c->token_defines_sub($keywords[-1])) {
      100        
1008 44         154 while($$rstr =~ m{\G\s*(:?\s*[\w]+)}gcs) {
1009 75         98 my $startpos = pos($$rstr);
1010 75 100       173 if (substr($$rstr, $startpos, 1) eq '(') {
1011 44         72 my @nest = '(';
1012 44         87 pos($$rstr) = $startpos + 1;
1013 44         63 my ($p, $c1);
1014 44         78 while(defined($p = pos($$rstr))) {
1015 103         136 $c1 = substr($$rstr, $p, 1);
1016 103 50       140 if ($c1 eq '\\') {
1017 0         0 pos($$rstr) = $p + 2;
1018 0         0 next;
1019             }
1020 103 100       166 if ($c1 eq ')') {
1021 50         57 pop @nest;
1022 50         81 pos($$rstr) = $p + 1;
1023 50 100       174 last unless @nest;
1024             }
1025 59 100       91 if ($c1 eq '(') {
1026 6         13 push @nest, $c1;
1027 6         10 pos($$rstr) = $p + 1;
1028 6         12 next;
1029             }
1030 53 100       138 $$rstr =~ m{\G([^\\()]+)}gc and next;
1031             }
1032             }
1033             }
1034 44         96 $token = substr($$rstr, $pos, pos($$rstr) - $pos);
1035 44         66 ($token_desc, $token_type) = ('ATTRIBUTE', '');
1036 44 100       92 if ($token =~ /^:prototype\(/) {
1037 2         6 $c->add_perl('5.020', ':prototype');
1038             }
1039 44         55 next;
1040             } else {
1041 162         411 pos($$rstr) = $pos + 1;
1042 162         382 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1043 162         280 next;
1044             }
1045             } elsif ($c1 eq '=') {
1046 1706         3035 my $c2 = substr($$rstr, $pos + 1, 1);
1047 1706 100       3598 if ($c2 eq '>') {
    100          
    100          
1048 600         1254 pos($$rstr) = $pos + 2;
1049 600         1189 ($token, $token_desc, $token_type) = ('=>', 'COMMA', 'OP');
1050 600 100 100     1539 if (@keywords and $prev_token_type eq 'KEYWORD' and $keywords[-1] eq $prev_token) {
      66        
1051 19         33 pop @keywords;
1052 19 100 100     76 if (!@keywords and ($current_scope & F_KEEP_TOKENS)) {
1053 1         3 $current_scope &= MASK_KEEP_TOKENS;
1054 1         3 @tokens = ();
1055             }
1056             }
1057 600         919 next;
1058             } elsif ($c2 eq '=') {
1059 74         136 pos($$rstr) = $pos + 2;
1060 74         133 ($token, $token_desc, $token_type) = ('==', '==', 'OP');
1061 74         102 next;
1062             } elsif ($c2 eq '~') {
1063 101         194 pos($$rstr) = $pos + 2;
1064 101         232 ($token, $token_desc, $token_type) = ('=~', '=~', 'OP');
1065 101         241 next;
1066             } else {
1067 931         1649 pos($$rstr) = $pos + 1;
1068 931         1779 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1069 931         1286 next;
1070             }
1071             } elsif ($c1 eq '>') {
1072 54         131 my $c2 = substr($$rstr, $pos + 1, 1);
1073 54 50       156 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         13 pos($$rstr) = $pos + 2;
1085 4         11 ($token, $token_desc, $token_type) = ('>=', '>=', 'OP');
1086 4         6 next;
1087             } else {
1088 50         98 pos($$rstr) = $pos + 1;
1089 50         122 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1090 50         72 next;
1091             }
1092             } elsif ($c1 eq '+') {
1093 134         253 my $c2 = substr($$rstr, $pos + 1, 1);
1094 134 100       345 if ($c2 eq '+') {
    100          
1095 19 50       62 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         43 pos($$rstr) = $pos + 2;
1101 19         48 ($token, $token_desc, $token_type) = ('++', '++', $prev_token_type);
1102 19         32 next;
1103             }
1104             } elsif ($c2 eq '=') {
1105 40         80 pos($$rstr) = $pos + 2;
1106 40         100 ($token, $token_desc, $token_type) = ('+=', '+=', 'OP');
1107 40         51 next;
1108             } else {
1109 75         141 pos($$rstr) = $pos + 1;
1110 75         152 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1111 75         101 next;
1112             }
1113             } elsif ($c1 eq '|') {
1114 93         212 my $c2 = substr($$rstr, $pos + 1, 1);
1115 93 100       237 if ($c2 eq '|') {
    100          
    100          
1116 85 100       237 if (substr($$rstr, $pos + 2, 1) eq '=') {
1117 17         39 pos($$rstr) = $pos + 3;
1118 17         43 ($token, $token_desc, $token_type) = ('||=', '||=', 'OP');
1119 17         32 next;
1120             } else {
1121 68         135 pos($$rstr) = $pos + 2;
1122 68         167 ($token, $token_desc, $token_type) = ('||', '||', 'OP');
1123 68         99 next;
1124             }
1125             } elsif ($c2 eq '=') {
1126 1         4 pos($$rstr) = $pos + 2;
1127 1         4 ($token, $token_desc, $token_type) = ('|=', '|=', 'OP');
1128 1         2 next;
1129             } elsif ($c2 eq '.') {
1130 2 100       7 if (substr($$rstr, $pos + 2, 1) eq '=') {
1131 1         2 pos($$rstr) = $pos + 3;
1132 1         3 ($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         6 $c->add_perl('5.022', '|.');
1138 2         4 next;
1139             } else {
1140 5         19 pos($$rstr) = $pos + 1;
1141 5         18 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1142 5         13 next;
1143             }
1144             } elsif ($c1 eq '^') {
1145 4         11 my $c2 = substr($$rstr, $pos + 1, 1);
1146 4 50       14 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       7 if (substr($$rstr, $pos + 2, 1) eq '=') {
1152 1         3 pos($$rstr) = $pos + 3;
1153 1         3 ($token, $token_desc, $token_type) = ('^.=', '^.=', 'OP');
1154             } else {
1155 1         3 pos($$rstr) = $pos + 2;
1156 1         3 ($token, $token_desc, $token_type) = ('^.', '^.', 'OP');
1157             }
1158 2         7 $c->add_perl('5.022', '^.');
1159 2         4 next;
1160             } else {
1161 2         5 pos($$rstr) = $pos + 1;
1162 2         4 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1163 2         5 next;
1164             }
1165             } elsif ($c1 eq '!') {
1166 51         138 my $c2 = substr($$rstr, $pos + 1, 1);
1167 51 100       216 if ($c2 eq '~') {
1168 5         13 pos($$rstr) = $pos + 2;
1169 5         12 ($token, $token_desc, $token_type) = ('!~', '!~', 'OP');
1170 5         8 next;
1171             } else {
1172 46         103 pos($$rstr) = $pos + 1;
1173 46         111 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1174 46         78 next;
1175             }
1176             } elsif ($c1 eq '~') {
1177 2         6 my $c2 = substr($$rstr, $pos + 1, 1);
1178 2 100       7 if ($c2 eq '~') {
    50          
1179 1         3 pos($$rstr) = $pos + 2;
1180 1         3 ($token, $token_desc, $token_type) = ('~~', '~~', 'OP');
1181 1         4 $c->add_perl('5.010', '~~');
1182 1         2 next;
1183             } elsif ($c2 eq '.') {
1184 1         4 pos($$rstr) = $pos + 2;
1185 1         4 ($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         2950 pos($$rstr) = $pos + 1;
1195 1389         2788 ($token, $token_desc, $token_type) = ($c1, 'COMMA', 'OP');
1196 1389         1795 next;
1197             } elsif ($c1 eq '?') {
1198 131         286 pos($$rstr) = $pos + 1;
1199 131         268 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1200 131         196 next;
1201             } elsif ($c1 eq '.') {
1202 195         408 my $c2 = substr($$rstr, $pos + 1, 1);
1203 195 100       476 if ($c2 eq '.') {
    100          
1204 20 100       74 if (substr($$rstr, $pos + 2, 1) eq '.') {
1205 15         39 pos($$rstr) = $pos + 3;
1206 15         34 ($token, $token_desc, $token_type) = ('...', '...', 'OP');
1207 15         71 $c->add_perl('5.012', '...');
1208 15         23 next;
1209             } else {
1210 5         12 pos($$rstr) = $pos + 2;
1211 5         14 ($token, $token_desc, $token_type) = ('..', '..', 'OP');
1212 5         11 next;
1213             }
1214             } elsif ($c2 eq '=') {
1215 26         60 pos($$rstr) = $pos + 2;
1216 26         68 ($token, $token_desc, $token_type) = ('.=', '.=', 'OP');
1217 26         43 next;
1218             } else {
1219 149         298 pos($$rstr) = $pos + 1;
1220 149         308 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1221 149         308 next;
1222             }
1223             } elsif ($c1 eq '0') {
1224 219         442 my $c2 = substr($$rstr, $pos + 1, 1);
1225 219 100       571 if ($c2 eq 'x') {
    50          
1226 4 50       28 if ($$rstr =~ m{\G(0x[0-9A-Fa-f_]+)}gc) {
1227 4         14 ($token, $token_desc, $token_type) = ($1, 'HEX NUMBER', 'EXPR');
1228 4         9 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 7655 100       21412 if ($$rstr =~ m{\G((?:0|[1-9][0-9_]*)(?:\.[0-9][0-9_]*)?)}gc) {
1239 650         1277 my $number = $1;
1240 650         1007 my $p = pos($$rstr);
1241 650         1087 my $n1 = substr($$rstr, $p, 1);
1242 650 100 33     2453 if ($n1 eq '.') {
    50          
1243 9 50       47 if ($$rstr =~ m{\G((?:\.[0-9_])+)}gc) {
    100          
1244 0         0 $number .= $1;
1245 0         0 ($token, $token_desc, $token_type) = ($number, 'VERSION_STRING', 'EXPR');
1246 0         0 next;
1247             } elsif (substr($$rstr, $p, 2) ne '..') {
1248 7         12 $number .= '.';
1249 7         13 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         1287 ($token, $token_desc, $token_type) = ($number, 'NUMBER', 'EXPR');
1257 650 100       1197 if ($prepend) {
1258 2         5 $token = "$prepend$token";
1259 2 50 33     10 pop @tokens if @tokens and $tokens[-1][0] eq $prepend;
1260 2 50 33     8 pop @scope_tokens if @scope_tokens and $scope_tokens[-1][0] eq $prepend;
1261             }
1262 650         976 next;
1263             }
1264              
1265 7005 100 100     19232 if ($prev_token_type ne 'ARROW' and ($prev_token_type ne 'KEYWORD' or !$c->token_expects_word($prev_token))) {
      100        
1266 5425 100 100     15497 if ($prev_token_type eq 'EXPR' or $prev_token_type eq 'VARIABLE') {
1267 330 100       766 if ($c1 eq 'x') {
1268 5 100       27 if ($$rstr =~ m{\G(x\b(?!\s*=>))}gc){
1269 3         11 ($token, $token_desc, $token_type) = ($1, $1, '');
1270 3         12 next;
1271             }
1272             }
1273             }
1274              
1275 5422 100       14972 if ($c1 eq 'q') {
    100          
    100          
    100          
    100          
1276 206         651 my $quotelike_re = $c->quotelike_re;
1277 206 100       2061 if ($$rstr =~ m{\G((?:$quotelike_re)\b(?!\s*=>))}gc) {
    100          
    50          
    100          
1278 96 50       273 if (my $quotelike = $self->_match_quotelike($c, $rstr, $1)) {
1279 96         195 ($token, $token_desc, $token_type) = ($quotelike, 'STRING', 'STRING');
1280 96         226 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       407 if (my $quotelike = $self->_match_quotelike($c, $rstr, $1)) {
1287 92         249 ($token, $token_desc, $token_type) = ($quotelike, 'QUOTED_WORD_LIST', 'EXPR');
1288 92         282 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       53 if (my $regexp = $self->_match_regexp($c, $rstr)) {
1303 16         45 ($token, $token_desc, $token_type) = ($regexp, 'qr', 'EXPR');
1304 16         42 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       1943 if ($$rstr =~ m{\G(m\b(?!\s*=>))}gc) {
1312 31 50       111 if (my $regexp = $self->_match_regexp($c, $rstr)) {
1313 31         81 ($token, $token_desc, $token_type) = ($regexp, 'm', 'EXPR');
1314 31         64 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       1611 if ($$rstr =~ m{\G(s\b(?!\s*=>))}gc) {
1322 53 50       152 if (my $regexp = $self->_match_substitute($c, $rstr)) {
1323 53         129 ($token, $token_desc, $token_type) = ($regexp, 's', 'EXPR');
1324 53         81 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       96 if ($$rstr =~ m{\G(tr\b(?!\s*=>))}gc) {
1332 3 50       13 if (my $trans = $self->_match_transliterate($c, $rstr)) {
1333 3         9 ($token, $token_desc, $token_type) = ($trans, 'tr', 'EXPR');
1334 3         7 next;
1335             } else {
1336 0         0 _debug("TRANSLITERATE ERROR: $@") if DEBUG;
1337 0         0 pos($$rstr) = $pos;
1338             }
1339             }
1340             } elsif ($c1 eq 'y') {
1341 4 100       17 if ($$rstr =~ m{\G(y\b(?!\s*=>))}gc) {
1342 2 50       10 if (my $trans = $self->_match_transliterate($c, $rstr)) {
1343 2         6 ($token, $token_desc, $token_type) = ($trans, 'y', 'EXPR');
1344 2         4 next;
1345             } else {
1346 0         0 _debug("TRANSLITERATE ERROR: $@") if DEBUG;
1347 0         0 pos($$rstr) = $pos;
1348             }
1349             }
1350             }
1351             }
1352              
1353 6709 100       16670 if ($$rstr =~ m{\G(\w+)}gc) {
1354 5993         11196 $token = $1;
1355 5993 100 66     18421 if ($prev_token_type eq 'ARROW') {
    100 66        
    100          
    100          
1356 521 100       1404 $$rstr =~ m{\G((?:(?:::|')\w+)+)\b}gc and $token .= $1;
1357 521         968 ($token_desc, $token_type) = ('METHOD', 'METHOD');
1358             } elsif ($token eq 'CORE') {
1359 3         9 ($token_desc, $token_type) = ('NAMESPACE', 'WORD');
1360             } elsif ($token eq 'format') {
1361 5 100       22 if ($$rstr =~ m{\G([^=]*?=[ \t]*\n.*?\n\.\n)}gcs) {
1362 4         18 $token .= $1;
1363 4         10 ($token_desc, $token_type) = ('FORMAT', '');
1364 4         5 $current_scope |= F_STATEMENT_END|F_EXPR_END;
1365 4         5 next;
1366             }
1367             } elsif ($c->token_is_keyword($token) and ($prev_token_type ne 'KEYWORD' or !$c->token_expects_word($prev_token) or ($prev_token eq 'sub' and $token eq 'BEGIN'))) {
1368 3508 100       7013 if ($c->token_is_op_keyword($token)) {
1369 164         313 ($token_desc, $token_type) = ($token, 'OP');
1370             } else {
1371 3344         5538 ($token_desc, $token_type) = ('KEYWORD', 'KEYWORD');
1372 3344         7552 $c->check_new_keyword($token);
1373 3344 100       7876 push @keywords, $token unless $token eq 'undef';
1374             }
1375             } else {
1376 1956 100 100     4264 if ($c1 eq 'v' and $token =~ /^v(?:0|[1-9][0-9]*)$/) {
1377 5 50       27 if ($$rstr =~ m{\G((?:\.[0-9][0-9_]*)+)}gc) {
1378 5         13 $token .= $1;
1379 5         13 ($token_desc, $token_type) = ('VERSION_STRING', 'EXPR');
1380 5         8 next;
1381             }
1382             }
1383 1951 100       6240 $$rstr =~ m{\G((?:(?:::|')\w+)+)\b}gc and $token .= $1;
1384 1951         3589 ($token_desc, $token_type) = ('WORD', 'WORD');
1385 1951 100       3347 if ($prepend) {
1386 49         116 $token = "$prepend$token";
1387 49 100 66     176 pop @tokens if @tokens and $tokens[-1][0] eq $prepend;
1388 49 100 66     169 pop @scope_tokens if @scope_tokens and $scope_tokens[-1][0] eq $prepend;
1389             }
1390             }
1391 5984         8804 next;
1392             }
1393              
1394             # ignore control characters
1395 716 50       1836 if ($$rstr =~ m{\G([[:cntrl:]]+)}gc) {
1396 0         0 next;
1397             }
1398              
1399 716 100       2188 if ($$rstr =~ m{\G([[:ascii:]]+)}gc) {
1400 1 50       3 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 715 50       1603 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 715 50       1669 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 715         1152 last;
1425             } continue {
1426 45614 50       67760 die "Aborted at $prev_pos" if $prev_pos == pos($$rstr);
1427 45614         50357 $prev_pos = pos($$rstr);
1428              
1429 45614 100       61762 if (defined $token) {
1430 26568 100 66     82561 if (!($current_scope & F_EXPR)) {
    100 33        
1431 5928         6233 _debug('BEGIN EXPR') if DEBUG;
1432 5928         6965 $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 3346         4904 @keywords = ();
1435 3346         3522 _debug('END EXPR') if DEBUG;
1436 3346         3894 $current_scope &= MASK_EXPR_END;
1437             }
1438 26568         31085 $prepend = undef;
1439              
1440 26568         27398 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 26568 100       37734 if ($parent_scope & F_KEEP_TOKENS) {
1446 841         1930 push @scope_tokens, [$token, $token_desc];
1447 841 100 66     2459 if ($token eq '-' or $token eq '+') {
1448 39         57 $prepend = $token;
1449             }
1450             }
1451 26568 100 100     102879 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 982         1325 $current_scope |= F_KEEP_TOKENS;
1453             }
1454 26568 100       50498 if ($c->token_expects_block($token)) {
1455 1091         1567 $waiting_for_a_block = 1;
1456             }
1457 26568 100 100     55179 if ($current_scope & F_EVAL or ($parent_scope & F_EVAL and (!@{$c->{stack}} or $c->{stack}[-1][0] ne '{'))) {
      100        
      100        
1458 134 100       371 if ($token_type eq 'STRING') {
    100          
    100          
1459 32 100       196 if ($token->[0] =~ /\b(?:(?:use|no)\s+[A-Za-z]|require\s+(?:q[qw]?.|['"])?[A-Za-z])/) {
1460 20         42 my $eval_string = $token->[0];
1461 20 50 33     129 if (defined $eval_string and $eval_string ne '') {
1462 20         51 $eval_string =~ s/\\(.)/$1/g;
1463 20         55 pos($eval_string) = 0;
1464 20         52 $c->{eval} = 1;
1465 20         46 my $saved_stack = $c->{stack};
1466 20         36 $c->{stack} = [];
1467 20         34 eval { $self->_scan($c, \$eval_string, (
  20         220  
1468             ($current_scope | $parent_scope | F_STRING_EVAL) &
1469             F_RESCAN
1470             ))};
1471 20         55 $c->{stack} = $saved_stack;
1472             }
1473             }
1474 32         54 $current_scope &= MASK_EVAL;
1475             } elsif ($token_desc eq 'HEREDOC') {
1476 1 50       13 if ($token->[0] =~ /\b(?:use|require|no)\s+[A-Za-z]/) {
1477 1         3 my $eval_string = $token->[0];
1478 1 50 33     5 if (defined $eval_string and $eval_string ne '') {
1479 1         3 $eval_string =~ s/\\(.)/$1/g;
1480 1         3 pos($eval_string) = 0;
1481 1         2 $c->{eval} = 1;
1482 1         2 my $saved_stack = $c->{stack};
1483 1         2 $c->{stack} = [];
1484 1         2 eval { $self->_scan($c, \$eval_string, (
  1         4  
1485             ($current_scope | $parent_scope | F_STRING_EVAL) &
1486             F_RESCAN
1487             ))};
1488 1         3 $c->{stack} = $saved_stack;
1489             }
1490             }
1491 1         2 $current_scope &= MASK_EVAL;
1492             } elsif ($token_type eq 'VARIABLE') {
1493 8         14 $current_scope &= MASK_EVAL;
1494             }
1495 134 100       300 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
1496             }
1497 26568 100       38863 if ($token eq 'eval') {
1498 51         78 $current_scope |= F_EVAL;
1499 51         113 $c->{eval} = 1;
1500             }
1501              
1502 26568 100       37003 if ($current_scope & F_KEEP_TOKENS) {
1503 4138         8760 push @tokens, [$token, $token_desc];
1504 4138 100 100     10761 if ($token eq '-' or $token eq '+') {
1505 12         30 $prepend = $token;
1506             }
1507 4138 100 100     8035 if ($token_type eq 'KEYWORD' and $has_sideff{$token}) {
1508 11         22 $current_scope |= F_SIDEFF;
1509             }
1510             }
1511 26568 100       35874 if ($stack) {
1512 2289         2768 push @{$c->{stack}}, $stack;
  2289         4051  
1513 2289         2757 _dump_stack($c, $stack->[0]) if DEBUG;
1514 2289         3180 my $child_scope = $current_scope | $parent_scope;
1515 2289 100 100     5711 if ($token eq '{' and $is_conditional{$stack->[2]}) {
1516 271         407 $child_scope |= F_CONDITIONAL
1517             }
1518 2289         17930 my $scanned_tokens = $self->_scan($c, $rstr, (
1519             $child_scope & F_RESCAN
1520             ));
1521 2289 100 100     5628 if ($token eq '{' and $current_scope & F_EVAL) {
1522 16         33 $current_scope &= MASK_EVAL;
1523 16 50       54 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
1524             }
1525 2289 100       4922 if ($current_scope & F_KEEP_TOKENS) {
    100          
1526 139   50     426 my $start = pop @tokens || '';
1527 139   50     349 my $end = pop @$scanned_tokens || '';
1528 139         729 push @tokens, [$scanned_tokens, "$start->[0]$end->[0]"];
1529             } elsif ($parent_scope & F_KEEP_TOKENS) {
1530 36   50     94 my $start = pop @scope_tokens || '';
1531 36   50     92 my $end = pop @$scanned_tokens || '';
1532 36         132 push @scope_tokens, [$scanned_tokens, "$start->[0]$end->[0]"];
1533             }
1534              
1535 2289 100 100     7734 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         478 pop @keywords;
1537             }
1538              
1539 2289 100 100     5965 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     1460 $current_scope |= F_STATEMENT_END unless @tokens and ($c->token_defines_sub($keywords[-1]) or $keywords[-1] eq 'eval');
      33        
1541             }
1542 2289         4233 $stack = undef;
1543             }
1544 26568 100       37467 if ($current_scope & F_STATEMENT_END) {
1545 4276 100 66     8600 if (($current_scope & F_KEEP_TOKENS) and @tokens) {
1546 947         1799 my $first_token = $tokens[0][0];
1547 947 100       1920 if ($first_token eq '->') {
1548 46         144 $first_token = $tokens[1][0];
1549             # ignore ->use and ->no
1550             # ->require may be from UNIVERSAL::require
1551 46 100 66     205 if ($first_token eq 'use' or $first_token eq 'no') {
1552 1         2 $first_token = '';
1553             }
1554             }
1555 947 100       2020 my $cond = (($current_scope | $parent_scope) & (F_CONDITIONAL|F_SIDEFF)) ? 1 : 0;
1556 947 100       2180 if (exists $c->{callback}{$first_token}) {
1557 716         1518 $c->{current_scope} = \$current_scope;
1558 716         1696 $c->{cond} = $cond;
1559 716         2578 $c->{callback}{$first_token}->($c, $rstr, \@tokens);
1560              
1561 716 50 33     2027 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 947 100       2109 if (exists $c->{keyword}{$first_token}) {
1569 185         429 $c->{current_scope} = \$current_scope;
1570 185         402 $c->{cond} = $cond;
1571 185         349 $tokens[0][1] = 'KEYWORD';
1572 185         543 $c->run_callback_for(keyword => $first_token, \@tokens);
1573             }
1574 947 100 66     3933 if (exists $c->{method}{$first_token} and $caller_package) {
1575 18         71 unshift @tokens, [$caller_package, 'WORD'];
1576 18         46 $c->{current_scope} = \$current_scope;
1577 18         30 $c->{cond} = $cond;
1578 18         61 $c->run_callback_for(method => $first_token, \@tokens);
1579             }
1580 947 100       3203 if ($current_scope & F_SIDEFF) {
1581 11         23 $current_scope &= MASK_SIDEFF;
1582 11         59 while(my $token = shift @tokens) {
1583 58 100       152 last if $has_sideff{$token->[0]};
1584             }
1585 11 100       29 $current_scope &= F_SIDEFF if grep {$has_sideff{$_->[0]}} @tokens;
  46         93  
1586 11 50       34 if (@tokens) {
1587 11         25 $first_token = $tokens[0][0];
1588 11 100       53 $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       40 if (exists $c->{keyword}{$first_token}) {
1595 1         2 $c->{current_scope} = \$current_scope;
1596 1         2 $c->{cond} = $cond;
1597 1         3 $tokens[0][1] = 'KEYWORD';
1598 1         4 $c->run_callback_for(keyword => $first_token, \@tokens);
1599             }
1600 11 50 33     84 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 4276         6034 @tokens = ();
1610 4276         5173 @keywords = ();
1611 4276         4940 $current_scope &= MASK_STATEMENT_END;
1612 4276         4846 $caller_package = undef;
1613 4276         5657 $token = $token_type = '';
1614 4276         4942 _debug('END SENTENSE') if DEBUG;
1615             }
1616 26568 100 100     39093 if ($unstack and @{$c->{stack}}) {
  2215         5416  
1617 2193         2846 my $stacked = pop @{$c->{stack}};
  2193         3722  
1618 2193         4150 my $stacked_type = substr($stacked->[0], -1);
1619 2193 50 66     11271 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         2475 _dump_stack($c, $unstack) if DEBUG;
1629 2193         2879 $current_scope |= F_SCOPE_END;
1630 2193         2923 $unstack = undef;
1631             }
1632              
1633 26568 100       40165 last if $current_scope & F_SCOPE_END;
1634 24302 100       34990 last if $c->{ended};
1635 24197 50 33     36409 last if $c->{last_found_by_skimming} and $c->{last_found_by_skimming} < pos($$rstr);
1636              
1637 24197         35021 ($prev_token, $prev_token_type) = ($token, $token_type);
1638             }
1639              
1640 43243 50 33     45458 if (@{$c->{errors}} and !($parent_scope & F_STRING_EVAL)) {
  43243         94339  
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 3088 100       5371 if (@tokens) {
1648 40 50       230 if (my $first_token = $tokens[0][0]) {
1649 40 100       170 if (exists $c->{callback}{$first_token}) {
1650 28         112 $c->{callback}{$first_token}->($c, $rstr, \@tokens);
1651             }
1652 40 100       122 if (exists $c->{keyword}{$first_token}) {
1653 9         18 $tokens[0][1] = 'KEYWORD';
1654 9         25 $c->run_callback_for(keyword => $first_token, \@tokens);
1655             }
1656             }
1657             }
1658              
1659 3088         3594 _dump_stack($c, "END SCOPE") if DEBUG;
1660              
1661 3088         7136 \@scope_tokens;
1662             }
1663              
1664             sub _match_quotelike {
1665 188     188   650 my ($self, $c, $rstr, $op) = @_;
1666              
1667             # '#' only works when it comes just after the op,
1668             # without prepending spaces
1669 188         1591 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1670              
1671 188 50       741 unless ($$rstr =~ m/\G(\S)/gc) {
1672 0         0 return _match_error($rstr, "No block delimiter found after $op");
1673             }
1674 188         385 my $ldel = $1;
1675 188         349 my $startpos = pos($$rstr);
1676              
1677 188 100       545 if ($ldel =~ /[[(<{]/) {
1678 135         397 my ($rdel, $re_skip) = _gen_rdel_and_re_skip($ldel);
1679 135         387 my @nest = ($ldel);
1680 135         214 my ($p, $c1);
1681 135         376 while(defined($p = pos($$rstr))) {
1682 360         594 $c1 = substr($$rstr, $p, 1);
1683 360 100       613 if ($c1 eq '\\') {
1684 28         43 pos($$rstr) = $p + 2;
1685 28         47 next;
1686             }
1687 332 100       651 if ($c1 eq $ldel) {
1688 15         33 pos($$rstr) = $p + 1;
1689 15         25 push @nest, $ldel;
1690 15         26 next;
1691             }
1692 317 100       572 if ($c1 eq $rdel) {
1693 150         327 pos($$rstr) = $p + 1;
1694 150         237 pop @nest;
1695 150 100       395 last unless @nest;
1696 15         25 next;
1697             }
1698 167 50       1375 $$rstr =~ m{\G$re_skip}gc and next;
1699 0         0 last;
1700             }
1701 135 50       397 return if @nest;
1702             } else {
1703 53         136 my $re = _gen_re_str_in_delims_with_end_delim($ldel);
1704 53 50       695 $$rstr =~ /\G$re/gcs or return;
1705             }
1706              
1707 188         379 my $endpos = pos($$rstr);
1708              
1709 188         954 return [substr($$rstr, $startpos, $endpos - $startpos - 1), $op];
1710             }
1711              
1712             sub _match_regexp0 { # //
1713 98     98   213 my ($self, $c, $rstr, $startpos, $token_type) = @_;
1714 98         209 pos($$rstr) = $startpos + 1;
1715              
1716 98         258 my $re_shortcut = _gen_re_regexp_shortcut('/');
1717 98 100 100     1073 $$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         279 $$rstr =~ m/\G([msixpodualgc]*)/gc;
1721 97         192 my $mod = $1;
1722              
1723 97         167 my $endpos = pos($$rstr);
1724              
1725 97         248 my $re = substr($$rstr, $startpos, $endpos - $startpos);
1726 97 100 100     271 if ($re =~ /\n/s and $mod !~ /x/) {
1727 1         4 return _match_error($rstr, "multiline without x");
1728             }
1729 96         270 return $re;
1730             }
1731              
1732             sub _match_regexp {
1733 47     47   279 my ($self, $c, $rstr) = @_;
1734 47   50     205 my $startpos = pos($$rstr) || 0;
1735              
1736             # '#' only works when it comes just after the op,
1737             # without prepending spaces
1738 47         434 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1739              
1740 47 50       155 unless ($$rstr =~ m/\G(\S)/gc) {
1741 0         0 return _match_error($rstr, "No block delimiter found");
1742             }
1743 47         126 my ($ldel, $rdel) = ($1, $1);
1744              
1745 47 100       141 if ($ldel =~ /[[(<{]/) {
1746 27         59 $rdel =~ tr/[({/;
1747             }
1748              
1749 47         163 my $re_shortcut = _gen_re_regexp_shortcut($ldel, $rdel);
1750 47 50 66     994 $$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         158 $$rstr =~ m/\G[msixpodualgc]*/gc;
1755 47         82 my $endpos = pos($$rstr);
1756              
1757 47         184 return substr($$rstr, $startpos, $endpos - $startpos);
1758             }
1759              
1760             sub _match_substitute {
1761 53     53   114 my ($self, $c, $rstr) = @_;
1762 53   50     132 my $startpos = pos($$rstr) || 0;
1763              
1764             # '#' only works when it comes just after the op,
1765             # without prepending spaces
1766 53         483 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1767              
1768 53 50       179 unless ($$rstr =~ m/\G(\S)/gc) {
1769 0         0 return _match_error($rstr, "No block delimiter found");
1770             }
1771 53         145 my ($ldel1, $rdel1) = ($1, $1);
1772              
1773 53 100       150 if ($ldel1 =~ /[[(<{]/) {
1774 22         40 $rdel1 =~ tr/[({/;
1775             }
1776              
1777 53         129 my $re_shortcut = _gen_re_regexp_shortcut($ldel1, $rdel1);
1778 53 50 100     1357 ($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       179 defined($self->_scan_re2($c, $rstr, $ldel1, 's')) or return;
1781 53         125 $$rstr =~ m/\G[msixpodualgcer]*/gc;
1782 53         85 my $endpos = pos($$rstr);
1783              
1784 53         196 return substr($$rstr, $startpos, $endpos - $startpos);
1785             }
1786              
1787             sub _match_transliterate {
1788 5     5   13 my ($self, $c, $rstr) = @_;
1789 5   50     15 my $startpos = pos($$rstr) || 0;
1790              
1791             # '#' only works when it comes just after the op,
1792             # without prepending spaces
1793 5         105 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1794              
1795 5 50       21 unless ($$rstr =~ m/\G(\S)/gc) {
1796 0         0 return _match_error($rstr, "No block delimiter found");
1797             }
1798 5         13 my $ldel1 = $1;
1799 5         9 my $ldel2;
1800              
1801 5 100       19 if ($ldel1 =~ /[[(<{]/) {
1802 1         2 (my $rdel1 = $ldel1) =~ tr/[({/;
1803 1         3 my $re = _gen_re_str_in_delims_with_end_delim($rdel1);
1804 1 50       19 $$rstr =~ /\G$re/gcs or return;
1805 1         31 $$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         13 my $re = _gen_re_str_in_delims_with_end_delim($ldel1);
1812 4 50       92 $$rstr =~ /\G$re/gcs or return;
1813 4         12 $ldel2 = $ldel1;
1814             }
1815              
1816 5 100       25 if ($ldel2 =~ /[[(<{]/) {
1817 1         3 (my $rdel2 = $ldel2) =~ tr/[({/;
1818 1         3 my $re = _gen_re_str_in_delims_with_end_delim($rdel2);
1819 1 50       20 $$rstr =~ /\G$re/gcs or return;
1820             } else {
1821 4         9 my $re = _gen_re_str_in_delims_with_end_delim($ldel2);
1822 4 50       86 $$rstr =~ /\G$re/gcs or return;
1823             }
1824              
1825 5         24 $$rstr =~ m/\G[cdsr]*/gc;
1826 5         10 my $endpos = pos($$rstr);
1827              
1828 5         24 return substr($$rstr, $startpos, $endpos - $startpos);
1829             }
1830              
1831             sub _match_heredoc {
1832 16     16   36 my ($self, $c, $rstr) = @_;
1833              
1834 16   50     52 my $startpos = pos($$rstr) || 0;
1835              
1836 16         75 $$rstr =~ m{\G(?:<<(~)?\s*)}gc;
1837 16 100       54 my $indent = $1 ? "\\s*" : "";
1838              
1839 16         22 my $label;
1840 16 100       332 if ($$rstr =~ m{\G\\?([A-Za-z_]\w*)}gc) {
    50          
1841 8         15 $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         29 $label = $+;
1848             } else {
1849 0         0 return;
1850             }
1851 16         47 $label =~ s/\\(.)/$1/g;
1852 16         32 my $extrapos = pos($$rstr);
1853 16         59 $$rstr =~ m{\G.*\n}gc;
1854 16         49 my $str1pos = pos($$rstr)--;
1855 16 100       571 unless ($$rstr =~ m{\G.*?\n$indent(?=\Q$label\E\n)}gcs) {
1856 2         9 return _match_error($rstr, qq{Missing here doc terminator ('$label')});
1857             }
1858 14         42 my $ldpos = pos($$rstr);
1859 14         948 $$rstr =~ m{\G\Q$label\E\n}gc;
1860 14         45 my $ld2pos = pos($$rstr);
1861              
1862 14         94 my $heredoc = [
1863             substr($$rstr, $str1pos, $ldpos-$str1pos),
1864             substr($$rstr, $startpos, $extrapos-$startpos),
1865             substr($$rstr, $ldpos, $ld2pos-$ldpos),
1866             ];
1867 14         106 substr($$rstr, $str1pos, $ld2pos - $str1pos) = '';
1868 14         95 pos($$rstr) = $extrapos;
1869 14 100       43 if ($indent) {
1870 1         4 $c->add_perl('5.026', '<<~');
1871             }
1872 14         49 return $heredoc;
1873             }
1874              
1875             sub _scan_re {
1876 126     126   364 my ($self, $c, $rstr, $ldel, $rdel, $op) = @_;
1877 126   50     293 my $startpos = pos($$rstr) || 0;
1878              
1879 126         173 _debug(" L $ldel R $rdel") if DEBUG_RE;
1880              
1881 126         190 my ($outer_opening_delimiter, $outer_closing_delimiter);
1882 126 100       235 if (@{$c->{stack}}) {
  126         326  
1883 110         288 ($outer_closing_delimiter = $outer_opening_delimiter = $c->{stack}[-1][0]) =~ tr/[({/;
1884             }
1885              
1886 126         261 my @nesting = ($ldel);
1887 126         173 my $multiline = 0;
1888 126         147 my $saw_sharp = 0;
1889 126         145 my $prev;
1890 126         189 my ($p, $c1);
1891 126         265 while (defined($p = pos($$rstr))) {
1892 5053         6165 $c1 = substr($$rstr, $p, 1);
1893 5053 100       6791 if ($c1 eq "\n") {
1894 271         486 $$rstr =~ m{\G\n\s*}gcs;
1895 271         294 $multiline = 1;
1896 271         273 $saw_sharp = 0;
1897             # _debug("CRLF") if DEBUG_RE;
1898 271         396 next;
1899             }
1900 4782 100 66     9412 if ($c1 eq ' ' or $c1 eq "\t") {
1901 696         1050 $$rstr =~ m{\G\s*}gc;
1902             # _debug("WHITESPACE") if DEBUG_RE;
1903 696         1058 next;
1904             }
1905 4086 100 100     5680 if ($c1 eq '#' and $rdel ne '#') {
1906 144 100 100     683 if ($multiline and $$rstr =~ m{\G(#[^\Q$rdel\E]*?)\n}gcs) {
1907 94         120 _debug(" comment $1") if DEBUG_RE
1908             } else {
1909 50         86 pos($$rstr) = $p + 1;
1910 50         78 $saw_sharp = 1;
1911 50         55 _debug(" saw #") if DEBUG_RE;
1912             }
1913 144         243 next;
1914             }
1915              
1916 3942 100 100     5789 if ($c1 eq '\\' and $rdel ne '\\') {
1917 416 50       1191 if ($$rstr =~ m/\G(\\.)/gcs) {
1918 416         463 _debug(" escaped $1") if DEBUG_RE;
1919 416         661 next;
1920             }
1921             }
1922              
1923 3526         3401 _debug(" looking @nesting: $c1") if DEBUG_RE;
1924              
1925 3526 100       4644 if ($c1 eq '[') {
1926             # character class may have other (ignorable) delimiters
1927 197 50       431 if ($$rstr =~ m/\G(\[\[:\w+?:\]\])/gcs) {
1928 0         0 _debug(" character class $1") if DEBUG_RE;
1929 0         0 next;
1930             }
1931 197 100       560 if ($$rstr =~ m/\G(\[[^\\\]]]*?(\\.[^\\\]]]*)*\])/gcs) {
1932 59         60 _debug(" character class: $1") if DEBUG_RE;
1933 59         84 next;
1934             }
1935             }
1936              
1937 3467 100       5412 if ($c1 eq $rdel) {
    100          
1938 156         314 pos($$rstr) = $p + 1;
1939 156 100       316 if ($saw_sharp) {
1940 39         59 my $tmp_pos = $p + 1;
1941 39 100       61 if ($op eq 's') {
1942 3         4 _debug(" looking for latter part") if DEBUG_RE;
1943 3         9 my $latter = $self->_scan_re2($c, $rstr, $ldel, $op);
1944 3 50       7 if (!defined $latter) {
1945 0         0 pos($$rstr) = $tmp_pos;
1946 0         0 next;
1947             }
1948 3         5 _debug(" latter: $latter") if DEBUG_RE;
1949             }
1950 39 100       99 if ($$rstr =~ m/\G[a-wyz]*x/) {
1951             # looks like an end of block
1952 2         3 _debug(" end of block $rdel (after #)") if DEBUG_RE;
1953 2         5 @nesting = ();
1954 2         6 pos($$rstr) = $tmp_pos;
1955 2         4 last;
1956             }
1957 37         58 pos($$rstr) = $tmp_pos;
1958 37 100       64 if ($multiline) {
1959 29         49 next; # part of a comment
1960             }
1961             }
1962 125         170 _debug(" end of block $rdel") if DEBUG_RE;
1963 125         177 my $expected = $rdel;
1964 125 100       227 if ($ldel ne $rdel) {
1965 44         69 $expected =~ tr/)}]>/({[
1966             }
1967 125         1169 while(my $nested = pop @nesting) {
1968 129 100       296 last if $nested eq $expected;
1969             }
1970 125 100       255 last unless @nesting;
1971 2         5 next;
1972             } elsif ($c1 eq $ldel) {
1973 30         50 pos($$rstr) = $p + 1;
1974 30 100 66     71 if ($multiline and $saw_sharp) {
1975             } else {
1976 2         3 _debug(" block $ldel") if DEBUG_RE;
1977 2         4 push @nesting, $ldel;
1978 2         2 next;
1979             }
1980             }
1981              
1982 3309 100       4663 if ($c1 eq '{') {
1983             # quantifier shouldn't be nested
1984 45 100       103 if ($$rstr =~ m/\G(\{[0-9]+(?:,(?:[0-9]+)?)?})/gcs) {
1985 4         5 _debug(" quantifier $1") if DEBUG_RE;
1986 4         6 next;
1987             }
1988             }
1989              
1990 3305 100       4362 if ($c1 eq '(') {
1991 407         583 my $c2 = substr($$rstr, $p + 1, 1);
1992 407 100 100     984 if ($c2 eq '?' and !($multiline and $saw_sharp)) {
      100        
1993             # code
1994 209 100       555 if ($$rstr =~ m/\G((\()\?+?)(?=\{)/gc) {
1995 70         83 _debug(" code $1") if DEBUG_RE;
1996 70         110 push @nesting, $2;
1997 70 50       82 unless (eval { $self->_scan($c, $rstr, F_EXPECTS_BRACKET); 1 }) {
  70         183  
  70         119  
1998 0         0 _debug("scan failed") if DEBUG_RE;
1999 0         0 return;
2000             }
2001 70         136 next;
2002             }
2003             # comment
2004 139 100       287 if ($$rstr =~ m{\G(\(\?\#[^\\\)]*(?:\\.[^\\\)]*)*\))}gcs) {
2005 10         11 _debug(" comment $1") if DEBUG_RE;
2006 10         18 next;
2007             }
2008             }
2009              
2010             # grouping may have (ignorable) <>
2011 327 50       818 if ($$rstr =~ m/\G((\()(?:<[!=]|<\w+?>|>)?)/gc) {
2012 327         371 _debug(" group $1") if DEBUG_RE;
2013 327         677 push @nesting, $2;
2014 327         527 next;
2015             }
2016             }
2017              
2018             # maybe variables (maybe not)
2019 2898 100 100     4233 if ($c1 eq '$' and substr($$rstr, $p + 1, 1) eq '{') {
2020 3         5 my @tmp_stack = @{$c->{stack}};
  3         7  
2021 3 50       5 next if eval { $self->_scan($c, $rstr, F_EXPECTS_BRACKET); 1 };
  3         9  
  3         9  
2022 0         0 pos($$rstr) = $p;
2023 0         0 $c->{stack} = \@tmp_stack;
2024             }
2025              
2026 2895 100       3850 if ($c1 eq ')') {
2027 397 100 66     933 if (@nesting and $nesting[-1] eq '(') {
2028 393         398 _debug(" end of group $c1") if DEBUG_RE;
2029 393         439 pop @nesting;
2030 393         733 pos($$rstr) = $p + 1;
2031 393         708 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       3320 if (!$op) {
2039 87 100 66     900 if ($outer_opening_delimiter and $c1 eq $outer_opening_delimiter) {
2040 1         2 push @nesting, $c1;
2041 1         3 pos($$rstr) = $p + 1;
2042 1         3 next;
2043             }
2044              
2045 86 100 66     158 if ($outer_closing_delimiter and $c1 eq $outer_closing_delimiter) {
2046 2 100 66     9 if (@nesting and $nesting[-1] eq $outer_opening_delimiter) {
2047 1         1 pop @nesting;
2048 1         2 pos($$rstr) = $p + 1;
2049 1         3 next;
2050             }
2051              
2052 1         4 return _match_error($rstr, "Outer closing delimiter: $outer_closing_delimiter is found");
2053             }
2054             }
2055              
2056 2499 50       5005 if ($$rstr =~ m/\G(\w+|.)/gcs) {
2057 2499         2565 _debug(" rest $1") if DEBUG_RE;
2058 2499         3549 next;
2059             }
2060 0         0 last;
2061             }
2062 125 50       351 if ($#nesting>=0) {
2063 0         0 return _match_error($rstr, "Unmatched opening bracket(s): ". join("..",@nesting)."..");
2064             }
2065              
2066 125         178 my $endpos = pos($$rstr);
2067              
2068 125         531 return substr($$rstr, $startpos, $endpos - $startpos);
2069             }
2070              
2071              
2072             sub _scan_re2 {
2073 56     56   146 my ($self, $c, $rstr, $ldel, $op) = @_;
2074 56         85 my $startpos = pos($$rstr);
2075              
2076 56 100       160 if ($ldel =~ /[[(<{]/) {
2077 23         131 $$rstr =~ /\G(?:$re_comment)/gcs;
2078              
2079 23 50       67 unless ($$rstr =~ /\G\s*(\S)/gc) {
2080 0         0 return _match_error($rstr, "Missing second block for quotelike $op");
2081             }
2082 23         56 $ldel = $1;
2083             }
2084              
2085 56 100       131 if ($ldel =~ /[[(<{]/) {
2086 23         52 my ($rdel, $re_skip) = _gen_rdel_and_re_skip($ldel);
2087 23         49 my @nest = $ldel;
2088 23         28 my ($p, $c1);
2089 23         70 while(defined($p = pos($$rstr))) {
2090 168         216 $c1 = substr($$rstr, $p, 1);
2091 168 100       238 if ($c1 eq '\\') {
2092 16         27 pos($$rstr) = $p + 2;
2093 16         23 next;
2094             }
2095 152 100       218 if ($c1 eq $ldel) {
2096 25         34 pos($$rstr) = $p + 1;
2097 25         39 push @nest, $ldel;
2098 25         36 next;
2099             }
2100 127 100       176 if ($c1 eq $rdel) {
2101 48         79 pos($$rstr) = $p + 1;
2102 48         74 pop @nest;
2103 48 100       86 last unless @nest;
2104 25         39 next;
2105             }
2106 79 50       327 $$rstr =~ m{\G$re_skip}gc and next;
2107 0         0 last;
2108             }
2109 23 50       45 return _match_error($rstr, "nesting mismatch: @nest") if @nest;
2110             } else {
2111 33         84 my $re = _gen_re_str_in_delims_with_end_delim($ldel);
2112 33 50       378 $$rstr =~ /\G$re/gcs or return;
2113             }
2114              
2115 56         110 my $endpos = pos($$rstr);
2116              
2117 56         188 return substr($$rstr, $startpos, $endpos - $startpos);
2118             }
2119              
2120             sub _use {
2121 644     644   1201 my ($c, $rstr, $tokens) = @_;
2122 644         861 _debug("USE TOKENS: ".(Data::Dump::dump($tokens))) if DEBUG;
2123 644         969 shift @$tokens; # discard 'use' itself
2124              
2125             # TODO: see if the token is WORD or not?
2126 644 50       1630 my $name_token = shift @$tokens or return;
2127 644         1201 my $name = $name_token->[0];
2128 644 50 33     3005 return if !defined $name or ref $name or $name eq '';
      33        
2129              
2130 644         1224 my $c1 = substr($name, 0, 1);
2131 644 100       1321 if ($c1 eq '5') {
2132 3         18 $c->add(perl => $name);
2133 3         302 return;
2134             }
2135 641 100       1258 if ($c1 eq 'v') {
2136 6         16 my $c2 = substr($name, 1, 1);
2137 6 100       18 if ($c2 eq '5') {
2138 1         4 $c->add(perl => $name);
2139 1         93 return;
2140             }
2141 5 50       14 if ($c2 eq '6') {
2142 0         0 $c->{perl6} = 1;
2143 0         0 $c->{ended} = 1;
2144 0         0 return;
2145             }
2146             }
2147 640 100       1847 if ($c->enables_utf8($name)) {
2148 18         54 $c->add($name => 0);
2149 18         413 $c->{utf8} = 1;
2150 18 100       36 if (!$c->{decoded}) {
2151 9         18 $c->{decoded} = 1;
2152 9         14 _debug("UTF8 IS ON") if DEBUG;
2153 9         109 utf8::decode($$rstr);
2154 9         84 pos($$rstr) = 0;
2155 9         30 $c->{ended} = $c->{redo} = 1;
2156             }
2157             }
2158              
2159 640 50       2106 if (is_module_name($name)) {
2160 640         1269 my $maybe_version_token = $tokens->[0];
2161 640         966 my $maybe_version_token_desc = $maybe_version_token->[1];
2162 640 100 66     2716 if ($maybe_version_token_desc and ($maybe_version_token_desc eq 'NUMBER' or $maybe_version_token_desc eq 'VERSION_STRING')) {
      100        
2163 34         123 $c->add($name => $maybe_version_token->[0]);
2164 34         3036 shift @$tokens;
2165             } else {
2166 606         1820 $c->add($name => 0);
2167             }
2168              
2169 640 100       21548 if (exists $sub_keywords{$name}) {
2170 5         9 $c->register_sub_keywords(@{$sub_keywords{$name}});
  5         25  
2171 5         57 $c->prototype_re(qr{\G(\((?:[^\\\(\)]*(?:\\.[^\\\(\)]*)*)\))});
2172             }
2173 640 100       1636 if (exists $filter_modules{$name}) {
2174 1         3 my $tmp = pos($$rstr);
2175 1         5 my $redo = $filter_modules{$name}->($rstr);
2176 1         2 pos($$rstr) = $tmp;
2177 1 50       3 $c->{ended} = $c->{redo} = 1 if $redo;
2178             }
2179             }
2180              
2181 640 100       1857 if ($c->has_callback_for(use => $name)) {
    100          
2182 307         618 eval { $c->run_callback_for(use => $name, $tokens) };
  307         834  
2183 307 50       2024 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         6  
2188 1 50       4 warn "Callback Error: $@" if $@;
2189             }
2190             }
2191              
2192 640 50       2012 if (exists $unsupported_packages{$name}) {
2193 0         0 $c->{found_unsupported_package} = $name;
2194             }
2195             }
2196              
2197             sub _require {
2198 69     69   151 my ($c, $rstr, $tokens) = @_;
2199 69         93 _debug("REQUIRE TOKENS: ".(Data::Dump::dump($tokens))) if DEBUG;
2200 69         112 shift @$tokens; # discard 'require' itself
2201              
2202             # TODO: see if the token is WORD or not?
2203 69 50       175 my $name_token = shift @$tokens or return;
2204 69         131 my $name = $name_token->[0];
2205 69 100       157 if (ref $name) {
2206 7         14 $name = $name->[0];
2207 7 100       46 return if $name =~ /\.pl$/i;
2208              
2209 5         20 $name =~ s|/|::|g;
2210 5         25 $name =~ s|\.pm$||i;
2211             }
2212 67 50 33     252 return if !defined $name or $name eq '';
2213              
2214 67         131 my $c1 = substr($name, 0, 1);
2215 67 100       165 if ($c1 eq '5') {
2216 1         5 $c->add_conditional(perl => $name);
2217 1         71 return;
2218             }
2219 66 100       154 if ($c1 eq 'v') {
2220 1         3 my $c2 = substr($name, 1, 1);
2221 1 50       3 if ($c2 eq '5') {
2222 1         5 $c->add_conditional(perl => $name);
2223 1         102 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       221 if (is_module_name($name)) {
2232 62         258 $c->add_conditional($name => 0);
2233 62         1748 return;
2234             }
2235             }
2236              
2237             sub _no {
2238 31     31   73 my ($c, $rstr, $tokens) = @_;
2239 31         52 _debug("NO TOKENS: ".(Data::Dump::dump($tokens))) if DEBUG;
2240 31         55 shift @$tokens; # discard 'no' itself
2241              
2242             # TODO: see if the token is WORD or not?
2243 31 50       95 my $name_token = shift @$tokens or return;
2244 31         65 my $name = $name_token->[0];
2245 31 50 33     206 return if !defined $name or ref $name or $name eq '';
      33        
2246              
2247 31         82 my $c1 = substr($name, 0, 1);
2248 31 100       73 if ($c1 eq '5') {
2249 1         5 $c->add_no(perl => $name);
2250 1         64 return;
2251             }
2252 30 100       84 if ($c1 eq 'v') {
2253 1         4 my $c2 = substr($name, 1, 1);
2254 1 50       3 if ($c2 eq '5') {
2255 1         5 $c->add_no(perl => $name);
2256 1         80 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       74 if ($name eq 'utf8') {
2265 0         0 $c->{utf8} = 0;
2266             }
2267              
2268 29 50       126 if (is_module_name($name)) {
2269 29         62 my $maybe_version_token = $tokens->[0];
2270 29         52 my $maybe_version_token_desc = $maybe_version_token->[1];
2271 29 100 66     163 if ($maybe_version_token_desc and ($maybe_version_token_desc eq 'NUMBER' or $maybe_version_token_desc eq 'VERSION_STRING')) {
      66        
2272 3         12 $c->add_no($name => $maybe_version_token->[0]);
2273 3         258 shift @$tokens;
2274             } else {
2275 26         116 $c->add_no($name => 0);
2276             }
2277             }
2278              
2279 29 100       942 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         4 return;
2283             }
2284             }
2285              
2286             1;
2287              
2288             __END__