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 89     89   5551536 use strict;
  89         934  
  89         2442  
4 89     89   445 use warnings;
  89         175  
  89         1956  
5 89     89   434 use Carp;
  89         169  
  89         4396  
6 89     89   38546 use Perl::PrereqScanner::NotQuiteLite::Context;
  89         276  
  89         3217  
7 89     89   604 use Perl::PrereqScanner::NotQuiteLite::Util;
  89         191  
  89         14039  
8              
9             our $VERSION = '0.9917';
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 89   50 89   677 use constant DEBUG => !!$ENV{PERL_PSNQL_DEBUG} || 0;
  89         242  
  89         6515  
23 89     89   585 use constant DEBUG_RE => DEBUG > 3 ? 1 : 0;
  89         232  
  89         9411  
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 89     89   615 no warnings 'redefine';
  89         230  
  89         1561455  
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   11 my $rstr = shift;
43 5         18 $@ = shift() . substr($$rstr, pos($$rstr), 100);
44 5         22 return;
45             }
46              
47             ### Global Variables To Be Sorted Out Later
48              
49             my %unsupported_packages = map {$_ => 1} qw(
50             );
51              
52             my %sub_keywords = (
53             'Function::Parameters' => [qw/fun method/],
54             'TryCatch' => [qw/try catch/],
55             );
56              
57             my %filter_modules = (
58             tt => sub { ${$_[0]} =~ s|\G.+?no\s*tt\s*;||s; 0; },
59             'Text::RewriteRules' => sub { ${$_[0]} =~ s|RULES.+?ENDRULES\n||gs; 1 },
60             );
61              
62             my %is_conditional = map {$_ => 1} qw(
63             if elsif unless else given when
64             for foreach while until
65             );
66              
67             my %ends_expr = map {$_ => 1} qw(
68             and or xor
69             if else elsif unless when default
70             for foreach while until
71             && || !~ =~ = += -= *= /= **= //= %= ^= |=
72             > < >= <= <> <=> cmp ge gt le lt eq ne ? :
73             );
74              
75             my %has_sideff = map {$_ => 1} qw(
76             and or xor && || //
77             if unless when
78             );
79              
80             # keywords that allow /regexp/ to follow directly
81             my %regexp_may_follow = map {$_ => 1} qw(
82             and or cmp if elsif unless eq ne
83             gt lt ge le for while until grep map not split when
84             return
85             );
86              
87             my $re_namespace = qr/(?:::|')?(?:[a-zA-Z0-9_]+(?:(?:::|')[a-zA-Z0-9_]+)*)/;
88             my $re_nonblock_chars = qr/[^\\\(\)\{\}\[\]\<\>\/"'`#q~,\s]*/;
89             my $re_variable = qr/
90             (?:$re_namespace)
91             | (?:\^[A-Z\]])
92             | (?:\{\^[A-Z0-9_]+\})
93             | (?:[_"\(\)<\\\&`'\+\-,.\/\%#:=~\|?!\@\*\[\]\^])
94             /x;
95             my $re_pod = qr/(
96             =[a-zA-Z]\w*\b
97             .*?
98             (?:(?:\n)
99             =cut\b.*?(?:\n|\z)|\z)
100             )/sx;
101             my $re_comment = qr/(?:\s*#[^\n]*?\n)*(?:\s*#[^\n]*?)(?:\n|$)/s;
102              
103             my $g_re_scalar_variable = qr{\G(\$(?:$re_variable))};
104             my $g_re_hash_shortcut = qr{\G(\{\s*(?:[\+\-]?\w+|(['"])[\w\s]+\2|(?:$re_nonblock_chars))\s*(?
105             my $g_re_prototype = qr{\G(\([^\)]*?\))};
106              
107             my %ReStrInDelims;
108             sub _gen_re_str_in_delims {
109 300     300   637 my $delim = shift;
110 300   66     1347 $ReStrInDelims{$delim} ||= do {
111 299 100       836 if ($delim eq '\\') {
112 2         10 qr/(?:[^\\]*(?:(?:\\\\)[^\\]*)*)/s;
113             } else {
114 297         672 $delim = quotemeta $delim;
115 297         6313 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   208 my $delim = shift;
127 96   66     438 $ReStrInDelimsWithEndDelim{$delim} ||= do {
128 33         167 my $re = _gen_re_str_in_delims($delim);
129 33         872 qr{$re\Q$delim\E};
130             };
131             }
132              
133             my %RdelSkip;
134             sub _gen_rdel_and_re_skip {
135 158     158   288 my $ldel = shift;
136 158   66     235 @{$RdelSkip{$ldel} ||= do {
  158         784  
137 37         135 (my $rdel = $ldel) =~ tr/[({/;
138 37         627 my $re_skip = qr{[^\Q$ldel$rdel\E\\]+};
139 37         321 [$rdel, $re_skip];
140             }};
141             }
142              
143             my %RegexpShortcut;
144             sub _gen_re_regexp_shortcut {
145 198     198   477 my ($ldel, $rdel) = @_;
146 198   66     682 $RegexpShortcut{$ldel} ||= do {
147 28         83 $ldel = quotemeta $ldel;
148 28 100       96 $rdel = $rdel ? quotemeta $rdel : $ldel;
149 28         1189 qr{(?:[^\\\(\)\{\}\[\]<>$ldel$rdel]*(?:\\.[^\\\(\)\[\]\{\}<>$ldel$rdel]*)*)$rdel};
150             };
151             }
152              
153             ############################
154              
155             my %LOADED;
156              
157             sub new {
158 739     739 1 2195007 my ($class, %args) = @_;
159              
160 739         1632 my %mapping;
161 739         3075 my @parsers = $class->_get_parsers($args{parsers});
162 739         1848 for my $parser (@parsers) {
163 22032 100       51303 if (!exists $LOADED{$parser}) {
164 2463         140929 eval "require $parser; 1";
165 2463 50       11938 if (my $error = $@) {
166 0 0       0 $parser->can('register') or die "Parser Error: $error";
167             }
168 2463 50       36520 $LOADED{$parser} = $parser->can('register') ? $parser->register(%args) : undef;
169             }
170 22032 50       49097 my $parser_mapping = $LOADED{$parser} or next;
171 22032         36116 for my $type (qw/use no keyword method/) {
172 88128 100       171428 next unless exists $parser_mapping->{$type};
173 24243         33645 for my $name (keys %{$parser_mapping->{$type}}) {
  24243         66317  
174             $mapping{$type}{$name} = [
175             $parser,
176 127535 100 100     433024 $parser_mapping->{$type}{$name},
177             (($type eq 'use' or $type eq 'no') ? ($name) : ()),
178             ];
179             }
180             }
181 22032 100       109452 if ($parser->can('register_fqfn')) {
182 2205         7719 my $fqfn_mapping = $parser->register_fqfn;
183 2205         6589 for my $name (keys %$fqfn_mapping) {
184 6612         25124 my ($module) = $name =~ /^(.+)::/;
185             $mapping{keyword}{$name} = [
186             $parser,
187 6612         22467 $fqfn_mapping->{$name},
188             $module,
189             ];
190             }
191             }
192             }
193 739         1955 $args{_} = \%mapping;
194              
195 739         4085 bless \%args, $class;
196             }
197              
198             sub _get_parsers {
199 739     739   1884 my ($class, $list) = @_;
200 739         1476 my @parsers;
201             my %should_ignore;
202 739 50       1430 for my $parser (@{$list || [qw/:default/]}) {
  739         2947  
203 743 50       3041 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 734         2182 push @parsers, map {"$class\::Parser::$_"} @BUNDLED_PARSERS;
  22020         48161  
208             } elsif ($parser eq ':default') {
209 5         16 push @parsers, map {"$class\::Parser::$_"} @DEFAULT_PARSERS;
  10         41  
210             } elsif ($parser =~ s/^\+//) {
211 1         4 push @parsers, $parser;
212             } elsif ($parser =~ s/^\-//) {
213 1         7 $should_ignore{"$class\::Parser\::$parser"} = 1;
214             } elsif ($parser =~ /^$class\::Parser::/) {
215 1         4 push @parsers, $parser;
216             } else {
217 1         5 push @parsers, "$class\::Parser\::$parser";
218             }
219             }
220 739         1816 grep {!$should_ignore{$_}} @parsers;
  22033         39342  
221             }
222              
223             sub scan_file {
224 72     72 1 204 my ($self, $file) = @_;
225 72         120 _debug("START SCANNING $file") if DEBUG;
226 72 50       239 print STDERR " Scanning $file\n" if $self->{verbose};
227 72 50       2922 open my $fh, '<', $file or croak "Can't open $file: $!";
228 72         236 my $code = do { local $/; <$fh> };
  72         387  
  72         2238  
229 72         310 $self->{file} = $file;
230 72         278 $self->scan_string($code);
231             }
232              
233             sub scan_string {
234 739     739 1 4320 my ($self, $string) = @_;
235              
236 739 50       1990 $string = '' unless defined $string;
237              
238 739         4626 my $c = Perl::PrereqScanner::NotQuiteLite::Context->new(%$self);
239              
240 739 50       2805 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 739 50       2648 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 739         2285 $string =~ s/\A(\x00\x00\xfe\xff|\xff\xfe\x00\x00|\xfe\xff|\xff\xfe)//s;
252              
253             # normalize
254 739         1259 if ("\n" eq "\015") {
255             $string =~ s/(?:\015?\012)/\n/gs;
256             } elsif ("\n" eq "\012") {
257 739         1808 $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 739         11771 $string =~ s/[ \t]+/ /g;
264 739         12187 $string =~ s/(?: *\n)+/\n/gs;
265              
266             # FIXME
267 739         2490 $c->{stack} = [];
268 739         1647 $c->{errors} = [];
269             $c->{callback} = {
270 739         3561 use => \&_use,
271             require => \&_require,
272             no => \&_no,
273             };
274 739         1909 $c->{wants_doc} = 0;
275              
276 739         2530 pos($string) = 0;
277              
278             {
279 739         1672 local $@;
  748         1395  
280 748         1615 eval { $self->_scan($c, \$string, 0) };
  748         2777  
281 748 50       2063 push @{$c->{errors}}, "Scan Error: $@" if $@;
  0         0  
282 748 100       2362 if ($c->{redo}) {
283 9         23 delete $c->{redo};
284 9         23 delete $c->{ended};
285 9         19 @{$c->{stack}} = ();
  9         25  
286 9         19 redo;
287             }
288             }
289              
290 739 100 66     1390 if (@{$c->{stack}} and !$c->{quick}) {
  739         2350  
291 1         504 require Data::Dump;
292 1         4541 push @{$c->{errors}}, Data::Dump::dump($c->{stack});
  1         8  
293             }
294              
295 739         19541 $c->remove_inner_packages_from_requirements;
296 739         3320 $c->merge_perl;
297              
298 739         10324 $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 3159     3159   7124 my ($self, $c, $rstr, $parent_scope) = @_;
320              
321 3159 100       4436 if (@{$c->{stack}} > 90) {
  3159         7878  
322 1         8 _error("deep recursion found");
323 1         9 $c->{ended} = 1;
324             }
325              
326 3159         4618 _dump_stack($c, "BEGIN SCOPE") if DEBUG;
327              
328             # found __DATA|END__ somewhere?
329 3159 100       6431 return $c if $c->{ended};
330              
331 3158         5113 my $wants_doc = $c->{wants_doc};
332 3158         4466 my $line_top = 1;
333 3158         4335 my $waiting_for_a_block;
334              
335 3158         4544 my $current_scope = 0;
336 3158         6572 my ($token, $token_desc, $token_type) = ('', '', '');
337 3158         5352 my ($prev_token, $prev_token_type) = ('', '');
338 3158         14094 my ($stack, $unstack);
339 3158         0 my (@keywords, @tokens, @scope_tokens);
340 3158         0 my $caller_package;
341 3158         0 my $prepend;
342 3158         0 my ($pos, $c1);
343 3158         4536 my $prev_pos = 0;
344 3158         7422 while(defined($pos = pos($$rstr))) {
345 47744         69988 $token = undef;
346              
347             # cache first letter for better performance
348 47744         78346 $c1 = substr($$rstr, $pos, 1);
349              
350 47744 100       79676 if ($line_top) {
351 7729 100       14494 if ($c1 eq '=') {
352 10 50       440 if ($$rstr =~ m/\G($re_pod)/gcsx) {
353 10 50       29 ($token, $token_desc, $token_type) = ($1, 'POD', '') if $wants_doc;
354 10         18 next;
355             }
356             }
357             }
358 47734 100       81143 if ($c1 eq "\n") {
359 4304         9394 pos($$rstr)++;
360 4304         7380 $line_top = 1;
361 4304         6502 next;
362             }
363              
364 43430         56074 $line_top = 0;
365             # ignore whitespaces
366 43430 100       232068 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 15121         30772 pos($$rstr)++;
368 15121         26624 next;
369             } elsif ($c1 eq '_') {
370 57         174 my $c2 = substr($$rstr, $pos + 1, 1);
371 57 100 100     259 if ($c2 eq '_' and $$rstr =~ m/\G(__(?:DATA|END)__\b)(?!\s*=>)/gc) {
372 1 50       4 if ($wants_doc) {
373 0         0 ($token, $token_desc, $token_type) = ($1, 'END_OF_CODE', '');
374 0         0 next;
375             } else {
376 1         4 $c->{ended} = 1;
377 1         3 last;
378             }
379             }
380             } elsif ($c1 eq '#') {
381 257 50       3946 if ($$rstr =~ m{\G($re_comment)}gcs) {
382 257 50       636 ($token, $token_desc, $token_type) = ($1, 'COMMENT', '') if $wants_doc;
383 257         401 $line_top = 1;
384 257         507 next;
385             }
386             } elsif ($c1 eq ';') {
387 2721         6342 pos($$rstr) = $pos + 1;
388 2721         6518 ($token, $token_desc, $token_type) = ($c1, ';', ';');
389 2721         4198 $current_scope |= F_STATEMENT_END|F_EXPR_END;
390 2721         4215 next;
391             } elsif ($c1 eq '$') {
392 3752         6534 my $c2 = substr($$rstr, $pos + 1, 1);
393 3752 100 66     34824 if ($c2 eq '#') {
    100 100        
    100          
    100          
    100          
    100          
394 32 100       537 if (substr($$rstr, $pos + 2, 1) eq '{') {
    100          
    100          
395 2 50       13 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         14 pos($$rstr) = $pos + 3;
400 2         9 ($token, $token_desc, $token_type) = ('$#{', '$#{', 'EXPR');
401 2         7 $stack = [$token, $pos, 'VARIABLE'];
402 2         5 next;
403             }
404             } elsif ($$rstr =~ m{\G(\$\#(?:$re_namespace))}gc) {
405 14         70 ($token, $token_desc, $token_type) = ($1, '$#NAME', 'EXPR');
406 14         44 next;
407             } elsif ($prev_token_type eq 'ARROW') {
408 2         9 my $c3 = substr($$rstr, $pos + 2, 1);
409 2 50       9 if ($c3 eq '*') {
410 2         7 pos($$rstr) = $pos + 3;
411 2         16 ($token, $token_desc, $token_type) = ('$#*', 'VARIABLE', 'VARIABLE');
412 2         12 $c->add_perl('5.020', '->$#*');
413 2         7 next;
414             }
415             } else {
416 14         92 pos($$rstr) = $pos + 2;
417 14         39 ($token, $token_desc, $token_type) = ('$#', 'SPECIAL_VARIABLE', 'EXPR');
418 14         27 next;
419             }
420             } elsif ($c2 eq '$') {
421 44 100       662 if ($$rstr =~ m{\G(\$(?:\$)+(?:$re_namespace))}gc) {
422 42         132 ($token, $token_desc, $token_type) = ($1, '$$NAME', 'VARIABLE');
423 42         80 next;
424             } else {
425 2         7 pos($$rstr) = $pos + 2;
426 2         7 ($token, $token_desc, $token_type) = ('$$', 'SPECIAL_VARIABLE', 'EXPR');
427 2         4 next;
428             }
429             } elsif ($c2 eq '{') {
430 10 100       63 if ($$rstr =~ m{\G(\$\{[\w\s]+\})}gc) {
    50          
431 2         8 ($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         24 pos($$rstr) = $pos + 2;
446 8         26 ($token, $token_desc, $token_type) = ('${', '${', 'VARIABLE');
447 8         20 $stack = [$token, $pos, 'VARIABLE'];
448             }
449 10 100       29 if ($parent_scope & F_EXPECTS_BRACKET) {
450 3         5 $current_scope |= F_SCOPE_END;
451             }
452 10         16 next;
453             } elsif ($c2 eq '*' and $prev_token_type eq 'ARROW') {
454 2         7 pos($$rstr) = $pos + 2;
455 2         16 ($token, $token_desc, $token_type) = ('$*', '$*', 'VARIABLE');
456 2         13 $c->add_perl('5.020', '->$*');
457 2         4 next;
458             } elsif ($c2 eq '+' or $c2 eq '-') {
459 2         8 pos($$rstr) = $pos + 2;
460 2         9 ($token, $token_desc, $token_type) = ('$'.$c2, 'SPECIAL_VARIABLE', 'VARIABLE');
461 2         12 $c->add_perl('5.010', '$'.$c2);
462 2         6 next;
463             } elsif ($$rstr =~ m{$g_re_scalar_variable}gc) {
464 3660         11096 ($token, $token_desc, $token_type) = ($1, '$NAME', 'VARIABLE');
465 3660         6177 next;
466             } else {
467 2         7 pos($$rstr) = $pos + 1;
468 2         8 ($token, $token_desc, $token_type) = ($c1, $c1, 'VARIABLE');
469 2         4 next;
470             }
471             } elsif ($c1 eq '@') {
472 317         681 my $c2 = substr($$rstr, $pos + 1, 1);
473 317 100 100     3054 if ($c2 eq '_' and $$rstr =~ m{\G\@_\b}gc) {
    100 100        
    100          
    100          
    100          
    100          
    50          
474 118         369 ($token, $token_desc, $token_type) = ('@_', 'SPECIAL_VARIABLE', 'VARIABLE');
475 118         228 next;
476             } elsif ($c2 eq '{') {
477 37 50       243 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         10 ($token, $token_desc, $token_type) = ($1, '@{^NAME}', 'VARIABLE');
484 2 50 33     9 if ($token eq '@{^CAPTURE}' or $token eq '@{^CAPTURE_ALL}') {
485 2         8 $c->add_perl('5.026', '@{^CAPTURE}');
486             }
487             } else {
488 35         102 pos($$rstr) = $pos + 2;
489 35         101 ($token, $token_desc, $token_type) = ('@{', '@{', 'VARIABLE');
490 35         104 $stack = [$token, $pos, 'VARIABLE'];
491             }
492 37 100       106 if ($prev_token_type eq 'ARROW') {
493 5         18 $c->add_perl('5.020', '->@{}');
494             }
495 37 50       107 if ($parent_scope & F_EXPECTS_BRACKET) {
496 0         0 $current_scope |= F_SCOPE_END;
497             }
498 37         67 next;
499             } elsif ($c2 eq '$') {
500 37 100       460 if ($$rstr =~ m{\G(\@\$(?:$re_namespace))}gc) {
501 35         107 ($token, $token_desc, $token_type) = ($1, '@$NAME', 'VARIABLE');
502 35         67 next;
503             } else {
504 2         7 pos($$rstr) = $pos + 2;
505 2         6 ($token, $token_desc, $token_type) = ('@$', '@$', 'VARIABLE');
506 2         4 next;
507             }
508             } elsif ($prev_token_type eq 'ARROW') {
509             # postderef
510 11 100       26 if ($c2 eq '*') {
511 5         14 pos($$rstr) = $pos + 2;
512 5         13 ($token, $token_desc, $token_type) = ('@*', '@*', 'VARIABLE');
513 5         19 $c->add_perl('5.020', '->@*');
514 5         8 next;
515             } else {
516 6         14 pos($$rstr) = $pos + 1;
517 6         18 ($token, $token_desc, $token_type) = ('@', '@', 'VARIABLE');
518 6         19 $c->add_perl('5.020', '->@');
519 6         10 next;
520             }
521             } elsif ($c2 eq '[') {
522 1         4 pos($$rstr) = $pos + 2;
523 1         3 ($token, $token_desc, $token_type) = ('@[', 'SPECIAL_VARIABLE', 'VARIABLE');
524 1         3 next;
525             } elsif ($c2 eq '+' or $c2 eq '-') {
526 2         8 pos($$rstr) = $pos + 2;
527 2         11 ($token, $token_desc, $token_type) = ('@'.$c2, 'SPECIAL_VARIABLE', 'VARIABLE');
528 2         11 $c->add_perl('5.010', '@'.$c2);
529 2         7 next;
530             } elsif ($$rstr =~ m{\G(\@(?:$re_namespace))}gc) {
531 111         419 ($token, $token_desc, $token_type) = ($1, '@NAME', 'VARIABLE');
532 111         237 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         274 my $c2 = substr($$rstr, $pos + 1, 1);
540 117 100 66     1901 if ($c2 eq '{') {
    100 66        
    100          
    100          
    100          
    100          
    50          
541 42 50       253 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         8 ($token, $token_desc, $token_type) = ($1, '%{^NAME}', 'VARIABLE');
545 2 50 66     11 if ($token eq '%{^CAPTURE}' or $token eq '%{^CAPTURE_ALL}') {
546 2         9 $c->add_perl('5.026', '%{^CAPTURE}');
547             }
548             } else {
549 40         108 pos($$rstr) = $pos + 2;
550 40         114 ($token, $token_desc, $token_type) = ('%{', '%{', 'VARIABLE');
551 40         135 $stack = [$token, $pos, 'VARIABLE'];
552             }
553 42 100       144 if ($prev_token_type eq 'ARROW') {
554 4         13 $c->add_perl('5.020', '->%{');
555             }
556 42 50       113 if ($parent_scope & F_EXPECTS_BRACKET) {
557 0         0 $current_scope |= F_SCOPE_END;
558             }
559 42         74 next;
560             } elsif ($c2 eq '=') {
561 1         5 pos($$rstr) = $pos + 2;
562 1         3 ($token, $token_desc, $token_type) = ('%=', '%=', 'OP');
563 1         3 next;
564             } elsif ($$rstr =~ m{\G(\%\$(?:$re_namespace))}gc) {
565 5         19 ($token, $token_desc, $token_type) = ($1, '%$NAME', 'VARIABLE');
566 5         10 next;
567             } elsif ($$rstr =~ m{\G(\%(?:$re_namespace))}gc) {
568 57         221 ($token, $token_desc, $token_type) = ($1, '%NAME', 'VARIABLE');
569 57         117 next;
570             } elsif ($prev_token_type eq 'VARIABLE' or $prev_token_type eq 'EXPR') {
571 4         15 pos($$rstr) = $pos + 1;
572 4         14 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
573 4         10 next;
574             } elsif ($prev_token_type eq 'ARROW') {
575 6 100       19 if ($c2 eq '*') {
576 2         7 pos($$rstr) = $pos + 2;
577 2         8 ($token, $token_desc, $token_type) = ('%*', '%*', 'VARIABLE');
578 2         11 $c->add_perl('5.020', '->%*');
579 2         6 next;
580             } else {
581 4         12 pos($$rstr) = $pos + 1;
582 4         13 ($token, $token_desc, $token_type) = ('%', '%', 'VARIABLE');
583 4         15 $c->add_perl('5.020', '->%');
584 4         9 next;
585             }
586             } elsif ($c2 eq '+' or $c2 eq '-') {
587 2         9 pos($$rstr) = $pos + 2;
588 2         10 ($token, $token_desc, $token_type) = ('%'.$c2, 'SPECIAL_VARIABLE', 'VARIABLE');
589 2         21 $c->add_perl('5.010', '%'.$c2);
590 2         7 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         194 my $c2 = substr($$rstr, $pos + 1, 1);
598 89 100       849 if ($c2 eq '{') {
    100          
    100          
    100          
599 15 100       81 if ($prev_token_type eq 'ARROW') {
    50          
600 2         8 pos($$rstr) = $pos + 2;
601 2         6 ($token, $token_desc, $token_type) = ('*{', '*{', 'VARIABLE');
602 2         9 $c->add_perl('5.020', '->*{}');
603 2         3 next;
604             } elsif ($$rstr =~ m{\G(\*\{[\w\s]+\})}gc) {
605 0         0 ($token, $token_desc, $token_type) = ($1, '*{NAME}', 'VARIABLE');
606 0 0 0     0 if ($prev_token eq 'KEYWORD' and $c->token_expects_fh_or_block_list($prev_token)) {
607 0         0 $token_type = '';
608 0         0 next;
609             }
610             } else {
611 13         34 pos($$rstr) = $pos + 2;
612 13         42 ($token, $token_desc, $token_type) = ('*{', '*{', 'VARIABLE');
613 13         28 $stack = [$token, $pos, 'VARIABLE'];
614             }
615 13 50       40 if ($parent_scope & F_EXPECTS_BRACKET) {
616 0         0 $current_scope |= F_SCOPE_END;
617             }
618 13         29 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         15 pos($$rstr) = $pos + 2;
626 2         9 ($token, $token_desc, $token_type) = ('**', '**', 'VARIABLE');
627 2         10 $c->add_perl('5.020', '->**');
628 2         5 next;
629             } else {
630 1         3 pos($$rstr) = $pos + 2;
631 1         4 ($token, $token_desc, $token_type) = ('**', '**', 'OP');
632 1         2 next;
633             }
634             } elsif ($c2 eq '=') {
635 2         7 pos($$rstr) = $pos + 2;
636 2         8 ($token, $token_desc, $token_type) = ('*=', '*=', 'OP');
637 2         4 next;
638             } elsif ($$rstr =~ m{\G(\*(?:$re_namespace))}gc) {
639 29         105 ($token, $token_desc, $token_type) = ($1, '*NAME', 'VARIABLE');
640 29         54 next;
641             } else {
642 40         119 pos($$rstr) = $pos + 1;
643 40         108 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
644 40         141 next;
645             }
646             } elsif ($c1 eq '&') {
647 129         290 my $c2 = substr($$rstr, $pos + 1, 1);
648 129 100       1335 if ($c2 eq '&') {
    50          
    100          
    100          
    100          
    100          
    100          
649 58         127 pos($$rstr) = $pos + 2;
650 58         153 ($token, $token_desc, $token_type) = ('&&', '&&', 'OP');
651 58         102 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       38 if ($$rstr =~ m{\G(\&\{[\w\s]+\})}gc) {
658 0         0 ($token, $token_desc, $token_type) = ($1, '&{NAME}', 'EXPR');
659             } else {
660 8         21 pos($$rstr) = $pos + 2;
661 8         24 ($token, $token_desc, $token_type) = ('&{', '&{', 'EXPR');
662 8         20 $stack = [$token, $pos, 'FUNC'];
663             }
664 8 50       84 if ($parent_scope & F_EXPECTS_BRACKET) {
665 0         0 $current_scope |= F_SCOPE_END;
666             }
667 8         17 next;
668             } elsif ($c2 eq '.') {
669 2 100       15 if (substr($$rstr, $pos + 2, 1) eq '=') {
670 1         4 pos($$rstr) = $pos + 3;
671 1         4 ($token, $token_desc, $token_type) = ('&.=', '&.=', 'OP');
672             } else {
673 1         6 pos($$rstr) = $pos + 2;
674 1         5 ($token, $token_desc, $token_type) = ('&.', '&.', 'OP');
675             }
676 2         10 $c->add_perl('5.022', '&.');
677 2         5 next;
678             } elsif ($$rstr =~ m{\G(\&(?:$re_namespace))}gc) {
679 48         162 ($token, $token_desc, $token_type) = ($1, '&NAME', 'EXPR');
680 48         102 next;
681             } elsif ($$rstr =~ m{\G(\&\$(?:$re_namespace))}gc) {
682 3         11 ($token, $token_desc, $token_type) = ($1, '&$NAME', 'EXPR');
683 3         6 next;
684             } elsif ($prev_token_type eq 'ARROW') {
685 2 50       30 if ($c2 eq '*') {
686 2         9 pos($$rstr) = $pos + 2;
687 2         8 ($token, $token_desc, $token_type) = ('&*', '&*', 'VARIABLE');
688 2         12 $c->add_perl('5.020', '->&*');
689 2         5 next;
690             }
691             } else {
692 8         33 pos($$rstr) = $pos + 1;
693 8         25 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
694 8         15 next;
695             }
696             } elsif ($c1 eq '\\') {
697 70         179 my $c2 = substr($$rstr, $pos + 1, 1);
698 70 50       164 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         171 pos($$rstr) = $pos + 1;
712 70         191 ($token, $token_desc, $token_type) = ($c1, $c1, '');
713 70         123 next;
714             }
715             } elsif ($c1 eq '-') {
716 1267         2676 my $c2 = substr($$rstr, $pos + 1, 1);
717 1267 100       2848 if ($c2 eq '>') {
    100          
    100          
    100          
718 1103         2304 pos($$rstr) = $pos + 2;
719 1103         2547 ($token, $token_desc, $token_type) = ('->', 'ARROW', 'ARROW');
720 1103 100 100     3483 if ($prev_token_type eq 'WORD' or $prev_token_type eq 'KEYWORD') {
721 51         200 $caller_package = $prev_token;
722 51         108 $current_scope |= F_KEEP_TOKENS;
723             }
724 1103         1790 next;
725             } elsif ($c2 eq '-') {
726 4         11 pos($$rstr) = $pos + 2;
727 4         16 ($token, $token_desc, $token_type) = ('--', '--', $prev_token_type);
728 4         8 next;
729             } elsif ($c2 eq '=') {
730 5         18 pos($$rstr) = $pos + 2;
731 5         15 ($token, $token_desc, $token_type) = ('-=', '-=', 'OP');
732 5         13 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         395 pos($$rstr) = $pos + 1;
738 151         414 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
739 151         263 next;
740             }
741             } elsif ($c1 eq q{"}) {
742 436 100       4366 if ($$rstr =~ m{\G(?:\"($re_str_in_double_quotes)\")}gcs) {
743 435         2003 ($token, $token_desc, $token_type) = ([$1, q{"}], 'STRING', 'STRING');
744 435         920 next;
745             }
746             } elsif ($c1 eq q{'}) {
747 859 50       7787 if ($$rstr =~ m{\G(?:\'($re_str_in_single_quotes)\')}gcs) {
748 859         3671 ($token, $token_desc, $token_type) = ([$1, q{'}], 'STRING', 'STRING');
749 859         1739 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     829 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       302 if (my $regexp = $self->_match_regexp0($c, $rstr, $pos, 'm')) {
759 96         243 ($token, $token_desc, $token_type) = ($regexp, 'REGEXP', 'EXPR');
760 96         188 next;
761             } else {
762             # the above may fail
763 1         3 _debug("REGEXP ERROR: $@") if DEBUG;
764 1         4 pos($$rstr) = $pos;
765             }
766             }
767 48 50 33     350 if (($prev_token_type eq '' or (!($current_scope & F_EXPR) and $prev_token_type eq 'WORD')) or ($prev_token_type eq 'KEYWORD' and @keywords and $prev_token eq $keywords[-1] and $regexp_may_follow{$prev_token})) {
      66        
      66        
      66        
      33        
      33        
768              
769 1 50       7 if (my $regexp = $self->_match_regexp0($c, $rstr, $pos)) {
770 0         0 ($token, $token_desc, $token_type) = ($regexp, 'REGEXP', 'EXPR');
771 0         0 next;
772             } else {
773             # the above may fail
774 1         2 _debug("REGEXP ERROR: $@") if DEBUG;
775 1         3 pos($$rstr) = $pos;
776             }
777             }
778 48         126 my $c2 = substr($$rstr, $pos + 1, 1);
779 48 100       121 if ($c2 eq '/') {
780 9 100       33 if (substr($$rstr, $pos + 2, 1) eq '=') {
781 2         9 pos($$rstr) = $pos + 3;
782 2         8 ($token, $token_desc, $token_type) = ('//=', '//=', 'OP');
783 2         28 $c->add_perl('5.010', '//=');
784 2         5 next;
785             } else {
786 7         17 pos($$rstr) = $pos + 2;
787 7         23 ($token, $token_desc, $token_type) = ('//', '//', 'OP');
788 7         30 $c->add_perl('5.010', '//');
789 7         13 next;
790             }
791             }
792 39 100       81 if ($c2 eq '=') { # this may be a part of /=.../
793 1         4 pos($$rstr) = $pos + 2;
794 1         4 ($token, $token_desc, $token_type) = ('/=', '/=', 'OP');
795 1         3 next;
796             } else {
797 38         86 pos($$rstr) = $pos + 1;
798 38         91 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
799 38         58 next;
800             }
801             } elsif ($c1 eq '{') {
802 1813 100       13667 if ($$rstr =~ m{$g_re_hash_shortcut}gc) {
803 879         2462 ($token, $token_desc) = ($1, '{EXPR}');
804 879 100       1837 if ($current_scope & F_EVAL) {
805 1         3 $current_scope &= MASK_EVAL;
806 1 50       6 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
807             }
808 879 100       1673 if ($parent_scope & F_EXPECTS_BRACKET) {
809 8         16 $current_scope |= F_SCOPE_END;
810 8         15 next;
811             }
812 871 100 100     2626 if ($prev_token_type eq 'ARROW' or $prev_token_type eq 'VARIABLE') {
    100 100        
    100          
813 755         1146 $token_type = 'VARIABLE';
814 755         1124 next;
815             } elsif ($waiting_for_a_block) {
816 82         158 $waiting_for_a_block = 0;
817 82 100 100     384 if (@keywords and $c->token_expects_block($keywords[0])) {
818 70         270 my $first_token = $keywords[0];
819 70         122 $current_scope |= F_EXPR_END;
820 70 100 100     290 if ($c->token_defines_sub($first_token) and $c->has_callback_for(sub => $first_token)) {
821 3         14 $c->run_callback_for(sub => $first_token, \@tokens);
822 3         7 $current_scope &= MASK_KEEP_TOKENS;
823 3         15 @tokens = ();
824             }
825             }
826 82         173 next;
827             } elsif ($prev_token_type eq 'KEYWORD' and $c->token_expects_fh_or_block_list($prev_token)) {
828 15         25 $token_type = '';
829 15         25 next;
830             } else {
831 19         35 $token_type = 'EXPR';
832 19         57 next;
833             }
834             }
835 934         2561 pos($$rstr) = $pos + 1;
836 934         2427 ($token, $token_desc) = ($c1, $c1);
837 934         1424 my $stack_owner;
838 934 100       2093 if (@keywords) {
839 741         1906 for(my $i = @keywords; $i > 0; $i--) {
840 773         1580 my $keyword = $keywords[$i - 1];
841 773 100       2038 if ($c->token_expects_block($keyword)) {
842 700         1170 $stack_owner = $keyword;
843 700 100 100     1848 if (@tokens and $c->token_defines_sub($keyword) and $c->has_callback_for(sub => $keyword)) {
      100        
844 54         244 $c->run_callback_for(sub => $keyword, \@tokens);
845 54         721 $current_scope &= MASK_KEEP_TOKENS;
846 54         152 @tokens = ();
847             }
848 700         1366 last;
849             }
850             }
851             }
852 934   100     3217 $stack = [$token, $pos, $stack_owner || ''];
853 934 100       2207 if ($parent_scope & F_EXPECTS_BRACKET) {
854 62         93 $current_scope |= F_SCOPE_END|F_STATEMENT_END|F_EXPR_END;
855 62         126 next;
856             }
857 872 100 100     3475 if ($prev_token_type eq 'ARROW' or $prev_token_type eq 'VARIABLE') {
    100          
858 35         55 $token_type = 'VARIABLE';
859             } elsif ($waiting_for_a_block) {
860 704         1043 $waiting_for_a_block = 0;
861             } else {
862 133 100       382 $token_type = (($current_scope | $parent_scope) & F_KEEP_TOKENS) ? 'EXPR' : '';
863             }
864 872         1453 next;
865             } elsif ($c1 eq '[') {
866 395 100       3288 if ($$rstr =~ m{\G(\[(?:$re_nonblock_chars)\])}gc) {
867 208         614 ($token, $token_desc, $token_type) = ($1, '[EXPR]', 'VARIABLE');
868 208         392 next;
869             } else {
870 187         540 pos($$rstr) = $pos + 1;
871 187         492 ($token, $token_desc, $token_type) = ($c1, $c1, 'VARIABLE');
872 187         432 $stack = [$token, $pos, 'VARIABLE'];
873 187         330 next;
874             }
875             } elsif ($c1 eq '(') {
876 1500         3913 my $prototype_re = $c->prototype_re;
877 1500 100 100     12036 if ($waiting_for_a_block and @keywords and $c->token_defines_sub($keywords[-1]) and $$rstr =~ m{$prototype_re}gc) {
    100 100        
      100        
878 115         365 my $proto = $1;
879 115 100       536 if ($proto =~ /^\([\\\$\@\%\&\[\]\*;\+]*\)$/) {
880 56         136 ($token, $token_desc, $token_type) = ($proto, '(PROTOTYPE)', '');
881             } else {
882 59         170 ($token, $token_desc, $token_type) = ($proto, '(SIGNATURES)', '');
883 59         208 $c->add_perl('5.020', 'signatures');
884             }
885 115         249 next;
886             } elsif ($$rstr =~ m{\G\(((?:$re_nonblock_chars)(?
887 295         1528 ($token, $token_desc, $token_type) = ([[[$1, 'EXPR']]], '()', 'EXPR');
888 295 100 100     1364 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       175 if ($prev_token eq 'eval') {
890 1         3 $current_scope &= MASK_EVAL;
891 1 50       6 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
892             }
893 54         149 pop @keywords;
894             }
895 295         610 next;
896             } else {
897 1090         3313 pos($$rstr) = $pos + 1;
898 1090         2740 ($token, $token_desc, $token_type) = ($c1, $c1, 'EXPR');
899 1090         1529 my $stack_owner;
900 1090 100       2315 if (@keywords) {
901 609         1609 for (my $i = @keywords; $i > 0; $i--) {
902 661         1381 my $keyword = $keywords[$i - 1];
903 661 100       1601 if ($c->token_expects_block($keyword)) {
904 215         440 $stack_owner = $keyword;
905 215         489 last;
906             }
907             }
908             }
909 1090   100     4062 $stack = [$token, $pos, $stack_owner || ''];
910 1090         2229 next;
911             }
912             } elsif ($c1 eq '}') {
913 1037         2292 pos($$rstr) = $pos + 1;
914 1037         2450 ($token, $token_desc, $token_type) = ($c1, $c1, '');
915 1037         1637 $unstack = $token;
916 1037         1731 $current_scope |= F_STATEMENT_END|F_EXPR_END;
917 1037         1670 next;
918             } elsif ($c1 eq ']') {
919 96         234 pos($$rstr) = $pos + 1;
920 96         287 ($token, $token_desc, $token_type) = ($c1, $c1, '');
921 96         160 $unstack = $token;
922 96         167 next;
923             } elsif ($c1 eq ')') {
924 1090         2597 pos($$rstr) = $pos + 1;
925 1090         2534 ($token, $token_desc, $token_type) = ($c1, $c1, '');
926 1090         1636 $unstack = $token;
927 1090         1595 next;
928             } elsif ($c1 eq '<') {
929 93         253 my $c2 = substr($$rstr, $pos + 1, 1);
930 93 100       629 if ($c2 eq '<'){
    100          
    100          
    100          
931 19 100       213 if ($$rstr =~ m{\G(<<(?:
    100          
932             \\. |
933             \w+ |
934             [./-] |
935             \[[^\]]*\] |
936             \{[^\}]*\} |
937             \* |
938             \? |
939             \~ |
940             \$ |
941             )*(?>)}gcx) {
942 1         5 ($token, $token_desc, $token_type) = ($1, '<>', 'EXPR');
943 1         5 $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       74 if (my $heredoc = $self->_match_heredoc($c, $rstr)) {
952 14         47 ($token, $token_desc, $token_type) = ($heredoc, 'HEREDOC', 'EXPR');
953 14         38 next;
954             } else {
955             # the above may fail
956 2         5 pos($$rstr) = $pos;
957             }
958             }
959 4 50       15 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         11 pos($$rstr) = $pos + 2;
965 4         10 ($token, $token_desc, $token_type) = ('<<', '<<', 'OP');
966 4         8 next;
967             }
968             } elsif ($c2 eq '=') {
969 10 100       34 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         3 next;
973             } else {
974 9         47 pos($$rstr) = $pos + 2;
975 9         38 ($token, $token_desc, $token_type) = ('<=', '<=', 'OP');
976 9         24 next;
977             }
978             } elsif ($c2 eq '>') {
979 1         4 pos($$rstr) = $pos + 2;
980 1         3 ($token, $token_desc, $token_type) = ('<>', '<>', 'OP');
981 1         3 next;
982             } elsif ($$rstr =~ m{\G(<(?:
983             \\. |
984             \w+ |
985             [./-] |
986             \[[^\]]*\] |
987             \{[^\}]*\} |
988             \* |
989             \? |
990             \~ |
991             \$ |
992             )*(?)}gcx) {
993 12         61 ($token, $token_desc, $token_type) = ($1, '', 'EXPR');
994 12         26 next;
995             } else {
996 51         142 pos($$rstr) = $pos + 1;
997 51         137 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
998 51         90 next;
999             }
1000             } elsif ($c1 eq ':') {
1001 293         669 my $c2 = substr($$rstr, $pos + 1, 1);
1002 293 100       712 if ($c2 eq ':') {
1003 21         60 pos($$rstr) = $pos + 2;
1004 21         58 ($token, $token_desc, $token_type) = ('::', '::', '');
1005 21         36 next;
1006             }
1007 272 100 100     1078 if ($waiting_for_a_block and @keywords and $c->token_defines_sub($keywords[-1])) {
      100        
1008 82         345 while($$rstr =~ m{\G\s*(:?\s*[\w]+)}gcs) {
1009 139         217 my $startpos = pos($$rstr);
1010 139 100       338 if (substr($$rstr, $startpos, 1) eq '(') {
1011 108         214 my @nest = '(';
1012 108         216 pos($$rstr) = $startpos + 1;
1013 108         182 my ($p, $c1);
1014 108         231 while(defined($p = pos($$rstr))) {
1015 231         358 $c1 = substr($$rstr, $p, 1);
1016 231 50       442 if ($c1 eq '\\') {
1017 0         0 pos($$rstr) = $p + 2;
1018 0         0 next;
1019             }
1020 231 100       388 if ($c1 eq ')') {
1021 114         153 pop @nest;
1022 114         224 pos($$rstr) = $p + 1;
1023 114 100       490 last unless @nest;
1024             }
1025 123 100       218 if ($c1 eq '(') {
1026 6         11 push @nest, $c1;
1027 6         18 pos($$rstr) = $p + 1;
1028 6         13 next;
1029             }
1030 117 100       391 $$rstr =~ m{\G([^\\()]+)}gc and next;
1031             }
1032             }
1033             }
1034 82         226 $token = substr($$rstr, $pos, pos($$rstr) - $pos);
1035 82         167 ($token_desc, $token_type) = ('ATTRIBUTE', '');
1036 82 100       194 if ($token =~ /^:prototype\(/) {
1037 2         9 $c->add_perl('5.020', ':prototype');
1038             }
1039 82         123 next;
1040             } else {
1041 190         455 pos($$rstr) = $pos + 1;
1042 190         513 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1043 190         328 next;
1044             }
1045             } elsif ($c1 eq '=') {
1046 1734         3540 my $c2 = substr($$rstr, $pos + 1, 1);
1047 1734 100       4035 if ($c2 eq '>') {
    100          
    100          
1048 600         1254 pos($$rstr) = $pos + 2;
1049 600         1463 ($token, $token_desc, $token_type) = ('=>', 'COMMA', 'OP');
1050 600 100 100     1882 if (@keywords and $prev_token_type eq 'KEYWORD' and $keywords[-1] eq $prev_token) {
      66        
1051 19         42 pop @keywords;
1052 19 100 100     88 if (!@keywords and ($current_scope & F_KEEP_TOKENS)) {
1053 1         3 $current_scope &= MASK_KEEP_TOKENS;
1054 1         3 @tokens = ();
1055             }
1056             }
1057 600         1039 next;
1058             } elsif ($c2 eq '=') {
1059 74         169 pos($$rstr) = $pos + 2;
1060 74         173 ($token, $token_desc, $token_type) = ('==', '==', 'OP');
1061 74         139 next;
1062             } elsif ($c2 eq '~') {
1063 101         236 pos($$rstr) = $pos + 2;
1064 101         242 ($token, $token_desc, $token_type) = ('=~', '=~', 'OP');
1065 101         213 next;
1066             } else {
1067 959         1951 pos($$rstr) = $pos + 1;
1068 959         2189 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1069 959         1508 next;
1070             }
1071             } elsif ($c1 eq '>') {
1072 54         140 my $c2 = substr($$rstr, $pos + 1, 1);
1073 54 50       182 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         12 pos($$rstr) = $pos + 2;
1085 4         14 ($token, $token_desc, $token_type) = ('>=', '>=', 'OP');
1086 4         10 next;
1087             } else {
1088 50         119 pos($$rstr) = $pos + 1;
1089 50         140 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1090 50         85 next;
1091             }
1092             } elsif ($c1 eq '+') {
1093 162         415 my $c2 = substr($$rstr, $pos + 1, 1);
1094 162 100       458 if ($c2 eq '+') {
    100          
1095 19 50       69 if (substr($$rstr, $pos + 2, 1) eq '=') {
1096 0         0 pos($$rstr) = $pos + 3;
1097 0         0 ($token, $token_desc, $token_type) = ('++=', '++=', 'OP');
1098 0         0 next;
1099             } else {
1100 19         51 pos($$rstr) = $pos + 2;
1101 19         59 ($token, $token_desc, $token_type) = ('++', '++', $prev_token_type);
1102 19         33 next;
1103             }
1104             } elsif ($c2 eq '=') {
1105 68         155 pos($$rstr) = $pos + 2;
1106 68         164 ($token, $token_desc, $token_type) = ('+=', '+=', 'OP');
1107 68         108 next;
1108             } else {
1109 75         180 pos($$rstr) = $pos + 1;
1110 75         193 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1111 75         120 next;
1112             }
1113             } elsif ($c1 eq '|') {
1114 93         233 my $c2 = substr($$rstr, $pos + 1, 1);
1115 93 100       237 if ($c2 eq '|') {
    100          
    100          
1116 85 100       261 if (substr($$rstr, $pos + 2, 1) eq '=') {
1117 17         42 pos($$rstr) = $pos + 3;
1118 17         48 ($token, $token_desc, $token_type) = ('||=', '||=', 'OP');
1119 17         23 next;
1120             } else {
1121 68         161 pos($$rstr) = $pos + 2;
1122 68         189 ($token, $token_desc, $token_type) = ('||', '||', 'OP');
1123 68         126 next;
1124             }
1125             } elsif ($c2 eq '=') {
1126 1         12 pos($$rstr) = $pos + 2;
1127 1         5 ($token, $token_desc, $token_type) = ('|=', '|=', 'OP');
1128 1         2 next;
1129             } elsif ($c2 eq '.') {
1130 2 100       10 if (substr($$rstr, $pos + 2, 1) eq '=') {
1131 1         4 pos($$rstr) = $pos + 3;
1132 1         3 ($token, $token_desc, $token_type) = ('|.=', '|.=', 'OP');
1133             } else {
1134 1         4 pos($$rstr) = $pos + 2;
1135 1         4 ($token, $token_desc, $token_type) = ('|.', '|.', 'OP');
1136             }
1137 2         10 $c->add_perl('5.022', '|.');
1138 2         5 next;
1139             } else {
1140 5         15 pos($$rstr) = $pos + 1;
1141 5         22 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1142 5         11 next;
1143             }
1144             } elsif ($c1 eq '^') {
1145 4         15 my $c2 = substr($$rstr, $pos + 1, 1);
1146 4 50       18 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       9 if (substr($$rstr, $pos + 2, 1) eq '=') {
1152 1         3 pos($$rstr) = $pos + 3;
1153 1         5 ($token, $token_desc, $token_type) = ('^.=', '^.=', 'OP');
1154             } else {
1155 1         5 pos($$rstr) = $pos + 2;
1156 1         6 ($token, $token_desc, $token_type) = ('^.', '^.', 'OP');
1157             }
1158 2         9 $c->add_perl('5.022', '^.');
1159 2         6 next;
1160             } else {
1161 2         5 pos($$rstr) = $pos + 1;
1162 2         5 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1163 2         5 next;
1164             }
1165             } elsif ($c1 eq '!') {
1166 51         129 my $c2 = substr($$rstr, $pos + 1, 1);
1167 51 100       122 if ($c2 eq '~') {
1168 5         15 pos($$rstr) = $pos + 2;
1169 5         15 ($token, $token_desc, $token_type) = ('!~', '!~', 'OP');
1170 5         9 next;
1171             } else {
1172 46         111 pos($$rstr) = $pos + 1;
1173 46         124 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1174 46         72 next;
1175             }
1176             } elsif ($c1 eq '~') {
1177 2         7 my $c2 = substr($$rstr, $pos + 1, 1);
1178 2 100       10 if ($c2 eq '~') {
    50          
1179 1         3 pos($$rstr) = $pos + 2;
1180 1         4 ($token, $token_desc, $token_type) = ('~~', '~~', 'OP');
1181 1         6 $c->add_perl('5.010', '~~');
1182 1         3 next;
1183             } elsif ($c2 eq '.') {
1184 1         4 pos($$rstr) = $pos + 2;
1185 1         4 ($token, $token_desc, $token_type) = ('~.', '~.', 'OP');
1186 1         6 $c->add_perl('5.022', '~.');
1187 1         3 next;
1188             } else {
1189 0         0 pos($$rstr) = $pos + 1;
1190 0         0 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1191 0         0 next;
1192             }
1193             } elsif ($c1 eq ',') {
1194 1393         3468 pos($$rstr) = $pos + 1;
1195 1393         3657 ($token, $token_desc, $token_type) = ($c1, 'COMMA', 'OP');
1196 1393         2202 next;
1197             } elsif ($c1 eq '?') {
1198 131         323 pos($$rstr) = $pos + 1;
1199 131         343 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1200 131         217 next;
1201             } elsif ($c1 eq '.') {
1202 195         443 my $c2 = substr($$rstr, $pos + 1, 1);
1203 195 100       553 if ($c2 eq '.') {
    100          
1204 20 100       74 if (substr($$rstr, $pos + 2, 1) eq '.') {
1205 15         40 pos($$rstr) = $pos + 3;
1206 15         47 ($token, $token_desc, $token_type) = ('...', '...', 'OP');
1207 15         59 $c->add_perl('5.012', '...');
1208 15         29 next;
1209             } else {
1210 5         18 pos($$rstr) = $pos + 2;
1211 5         18 ($token, $token_desc, $token_type) = ('..', '..', 'OP');
1212 5         22 next;
1213             }
1214             } elsif ($c2 eq '=') {
1215 26         76 pos($$rstr) = $pos + 2;
1216 26         72 ($token, $token_desc, $token_type) = ('.=', '.=', 'OP');
1217 26         41 next;
1218             } else {
1219 149         414 pos($$rstr) = $pos + 1;
1220 149         378 ($token, $token_desc, $token_type) = ($c1, $c1, 'OP');
1221 149         345 next;
1222             }
1223             } elsif ($c1 eq '0') {
1224 247         568 my $c2 = substr($$rstr, $pos + 1, 1);
1225 247 100       828 if ($c2 eq 'x') {
    50          
1226 4 50       31 if ($$rstr =~ m{\G(0x[0-9A-Fa-f_]+)}gc) {
1227 4         16 ($token, $token_desc, $token_type) = ($1, 'HEX NUMBER', 'EXPR');
1228 4         10 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 8011 100       27701 if ($$rstr =~ m{\G((?:0|[1-9][0-9_]*)(?:\.[0-9][0-9_]*)?)}gc) {
1239 700         1719 my $number = $1;
1240 700         1186 my $p = pos($$rstr);
1241 700         1366 my $n1 = substr($$rstr, $p, 1);
1242 700 100 33     2931 if ($n1 eq '.') {
    50          
1243 9 50       52 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         11 $number .= '.';
1249 7         17 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 700         1671 ($token, $token_desc, $token_type) = ($number, 'NUMBER', 'EXPR');
1257 700 100       1456 if ($prepend) {
1258 2         7 $token = "$prepend$token";
1259 2 50 33     15 pop @tokens if @tokens and $tokens[-1][0] eq $prepend;
1260 2 50 33     18 pop @scope_tokens if @scope_tokens and $scope_tokens[-1][0] eq $prepend;
1261             }
1262 700         1287 next;
1263             }
1264              
1265 7311 100 100     24365 if ($prev_token_type ne 'ARROW' and ($prev_token_type ne 'KEYWORD' or !$c->token_expects_word($prev_token))) {
      100        
1266 5627 100 100     17776 if ($prev_token_type eq 'EXPR' or $prev_token_type eq 'VARIABLE') {
1267 330 100       754 if ($c1 eq 'x') {
1268 5 100       27 if ($$rstr =~ m{\G(x\b(?!\s*=>))}gc){
1269 3         12 ($token, $token_desc, $token_type) = ($1, $1, '');
1270 3         14 next;
1271             }
1272             }
1273             }
1274              
1275 5624 100       17987 if ($c1 eq 'q') {
    100          
    100          
    100          
    100          
1276 206         763 my $quotelike_re = $c->quotelike_re;
1277 206 100       2364 if ($$rstr =~ m{\G((?:$quotelike_re)\b(?!\s*=>))}gc) {
    100          
    50          
    100          
1278 96 50       299 if (my $quotelike = $self->_match_quotelike($c, $rstr, $1)) {
1279 96         238 ($token, $token_desc, $token_type) = ($quotelike, 'STRING', 'STRING');
1280 96         256 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       461 if (my $quotelike = $self->_match_quotelike($c, $rstr, $1)) {
1287 92         293 ($token, $token_desc, $token_type) = ($quotelike, 'QUOTED_WORD_LIST', 'EXPR');
1288 92         361 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       97 if (my $regexp = $self->_match_regexp($c, $rstr)) {
1303 16         49 ($token, $token_desc, $token_type) = ($regexp, 'qr', 'EXPR');
1304 16         53 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 651 100       2005 if ($$rstr =~ m{\G(m\b(?!\s*=>))}gc) {
1312 31 50       130 if (my $regexp = $self->_match_regexp($c, $rstr)) {
1313 31         95 ($token, $token_desc, $token_type) = ($regexp, 'm', 'EXPR');
1314 31         63 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       1859 if ($$rstr =~ m{\G(s\b(?!\s*=>))}gc) {
1322 53 50       178 if (my $regexp = $self->_match_substitute($c, $rstr)) {
1323 53         139 ($token, $token_desc, $token_type) = ($regexp, 's', 'EXPR');
1324 53         96 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       108 if ($$rstr =~ m{\G(tr\b(?!\s*=>))}gc) {
1332 3 50       14 if (my $trans = $self->_match_transliterate($c, $rstr)) {
1333 3         11 ($token, $token_desc, $token_type) = ($trans, 'tr', 'EXPR');
1334 3         5 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       21 if ($$rstr =~ m{\G(y\b(?!\s*=>))}gc) {
1342 2 50       9 if (my $trans = $self->_match_transliterate($c, $rstr)) {
1343 2         6 ($token, $token_desc, $token_type) = ($trans, 'y', 'EXPR');
1344 2         5 next;
1345             } else {
1346 0         0 _debug("TRANSLITERATE ERROR: $@") if DEBUG;
1347 0         0 pos($$rstr) = $pos;
1348             }
1349             }
1350             }
1351             }
1352              
1353 7015 100       21480 if ($$rstr =~ m{\G(\w+)}gc) {
1354 6257         14061 $token = $1;
1355 6257 100 66     23115 if ($prev_token_type eq 'ARROW') {
    100 66        
    100          
    100          
1356 521 100       1463 $$rstr =~ m{\G((?:(?:::|')\w+)+)\b}gc and $token .= $1;
1357 521         1142 ($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       29 if ($$rstr =~ m{\G([^=]*?=[ \t]*\n.*?\n\.\n)}gcs) {
1362 4         15 $token .= $1;
1363 4         11 ($token_desc, $token_type) = ('FORMAT', '');
1364 4         7 $current_scope |= F_STATEMENT_END|F_EXPR_END;
1365 4         7 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 3612 100       8407 if ($c->token_is_op_keyword($token)) {
1369 164         354 ($token_desc, $token_type) = ($token, 'OP');
1370             } else {
1371 3448         6739 ($token_desc, $token_type) = ('KEYWORD', 'KEYWORD');
1372 3448         9019 $c->check_new_keyword($token);
1373 3448 100       9860 push @keywords, $token unless $token eq 'undef';
1374             }
1375             } else {
1376 2116 100 100     5567 if ($c1 eq 'v' and $token =~ /^v(?:0|[1-9][0-9]*)$/) {
1377 5 50       39 if ($$rstr =~ m{\G((?:\.[0-9][0-9_]*)+)}gc) {
1378 5         18 $token .= $1;
1379 5         14 ($token_desc, $token_type) = ('VERSION_STRING', 'EXPR');
1380 5         11 next;
1381             }
1382             }
1383 2111 100       7885 $$rstr =~ m{\G((?:(?:::|')\w+)+)\b}gc and $token .= $1;
1384 2111         4538 ($token_desc, $token_type) = ('WORD', 'WORD');
1385 2111 100       4271 if ($prepend) {
1386 49         147 $token = "$prepend$token";
1387 49 100 66     194 pop @tokens if @tokens and $tokens[-1][0] eq $prepend;
1388 49 100 66     215 pop @scope_tokens if @scope_tokens and $scope_tokens[-1][0] eq $prepend;
1389             }
1390             }
1391 6248         11420 next;
1392             }
1393              
1394             # ignore control characters
1395 758 50       2154 if ($$rstr =~ m{\G([[:cntrl:]]+)}gc) {
1396 0         0 next;
1397             }
1398              
1399 758 100       2040 if ($$rstr =~ m{\G([[:ascii:]]+)}gc) {
1400 1 50       5 last if $parent_scope & F_STRING_EVAL;
1401 0         0 _error("UNKNOWN: $1");
1402 0         0 push @{$c->{errors}}, qq{"$1"};
  0         0  
1403 0         0 $token = $1;
1404 0         0 next;
1405             }
1406 757 50       2007 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 757 50       2067 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 757         1489 last;
1425             } continue {
1426 46985 50       87045 die "Aborted at $prev_pos" if $prev_pos == pos($$rstr);
1427 46985         64035 $prev_pos = pos($$rstr);
1428              
1429 46985 100       79362 if (defined $token) {
1430 27293 100 66     100855 if (!($current_scope & F_EXPR)) {
    100 33        
1431 6116         7881 _debug('BEGIN EXPR') if DEBUG;
1432 6116         8973 $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 3477         5924 @keywords = ();
1435 3477         4582 _debug('END EXPR') if DEBUG;
1436 3477         5001 $current_scope &= MASK_EXPR_END;
1437             }
1438 27293         38033 $prepend = undef;
1439              
1440 27293         33971 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 27293 100       47062 if ($parent_scope & F_KEEP_TOKENS) {
1446 841         2413 push @scope_tokens, [$token, $token_desc];
1447 841 100 66     3167 if ($token eq '-' or $token eq '+') {
1448 39         69 $prepend = $token;
1449             }
1450             }
1451 27293 100 100     126863 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 1072         1896 $current_scope |= F_KEEP_TOKENS;
1453             }
1454 27293 100       63156 if ($c->token_expects_block($token)) {
1455 1153         1872 $waiting_for_a_block = 1;
1456             }
1457 27293 100 100     68709 if ($current_scope & F_EVAL or ($parent_scope & F_EVAL and (!@{$c->{stack}} or $c->{stack}[-1][0] ne '{'))) {
      100        
      100        
1458 134 100       483 if ($token_type eq 'STRING') {
    100          
    100          
1459 32 100       220 if ($token->[0] =~ /\b(?:(?:use|no)\s+[A-Za-z]|require\s+(?:q[qw]?.|['"])?[A-Za-z])/) {
1460 20         60 my $eval_string = $token->[0];
1461 20 50 33     103 if (defined $eval_string and $eval_string ne '') {
1462 20         54 $eval_string =~ s/\\(.)/$1/g;
1463 20         60 pos($eval_string) = 0;
1464 20         55 $c->{eval} = 1;
1465 20         52 my $saved_stack = $c->{stack};
1466 20         45 $c->{stack} = [];
1467 20         40 eval { $self->_scan($c, \$eval_string, (
  20         291  
1468             ($current_scope | $parent_scope | F_STRING_EVAL) &
1469             F_RESCAN
1470             ))};
1471 20         68 $c->{stack} = $saved_stack;
1472             }
1473             }
1474 32         72 $current_scope &= MASK_EVAL;
1475             } elsif ($token_desc eq 'HEREDOC') {
1476 1 50       15 if ($token->[0] =~ /\b(?:use|require|no)\s+[A-Za-z]/) {
1477 1         4 my $eval_string = $token->[0];
1478 1 50 33     7 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         5 $c->{eval} = 1;
1482 1         2 my $saved_stack = $c->{stack};
1483 1         3 $c->{stack} = [];
1484 1         2 eval { $self->_scan($c, \$eval_string, (
  1         6  
1485             ($current_scope | $parent_scope | F_STRING_EVAL) &
1486             F_RESCAN
1487             ))};
1488 1         4 $c->{stack} = $saved_stack;
1489             }
1490             }
1491 1         3 $current_scope &= MASK_EVAL;
1492             } elsif ($token_type eq 'VARIABLE') {
1493 8         17 $current_scope &= MASK_EVAL;
1494             }
1495 134 100       401 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
1496             }
1497 27293 100       48213 if ($token eq 'eval') {
1498 51         102 $current_scope |= F_EVAL;
1499 51         146 $c->{eval} = 1;
1500             }
1501              
1502 27293 100       46882 if ($current_scope & F_KEEP_TOKENS) {
1503 4457         12544 push @tokens, [$token, $token_desc];
1504 4457 100 100     14998 if ($token eq '-' or $token eq '+') {
1505 12         27 $prepend = $token;
1506             }
1507 4457 100 100     11079 if ($token_type eq 'KEYWORD' and $has_sideff{$token}) {
1508 11         28 $current_scope |= F_SIDEFF;
1509             }
1510             }
1511 27293 100       44937 if ($stack) {
1512 2317         3282 push @{$c->{stack}}, $stack;
  2317         4852  
1513 2317         3263 _dump_stack($c, $stack->[0]) if DEBUG;
1514 2317         3630 my $child_scope = $current_scope | $parent_scope;
1515 2317 100 100     6571 if ($token eq '{' and $is_conditional{$stack->[2]}) {
1516 271         460 $child_scope |= F_CONDITIONAL
1517             }
1518 2317         19495 my $scanned_tokens = $self->_scan($c, $rstr, (
1519             $child_scope & F_RESCAN
1520             ));
1521 2317 100 100     6364 if ($token eq '{' and $current_scope & F_EVAL) {
1522 16         32 $current_scope &= MASK_EVAL;
1523 16 50       60 $c->{eval} = ($current_scope | $parent_scope) & F_EVAL ? 1 : 0;
1524             }
1525 2317 100       5673 if ($current_scope & F_KEEP_TOKENS) {
    100          
1526 139   50     492 my $start = pop @tokens || '';
1527 139   50     394 my $end = pop @$scanned_tokens || '';
1528 139         658 push @tokens, [$scanned_tokens, "$start->[0]$end->[0]"];
1529             } elsif ($parent_scope & F_KEEP_TOKENS) {
1530 36   50     107 my $start = pop @scope_tokens || '';
1531 36   50     118 my $end = pop @$scanned_tokens || '';
1532 36         169 push @scope_tokens, [$scanned_tokens, "$start->[0]$end->[0]"];
1533             }
1534              
1535 2317 100 100     8830 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         507 pop @keywords;
1537             }
1538              
1539 2317 100 100     7122 if ($stack->[0] eq '{' and @keywords and $c->token_expects_block($keywords[0]) and !$c->token_expects_block_list($keywords[-1])) {
      100        
      100        
1540 639 50 0     1730 $current_scope |= F_STATEMENT_END unless @tokens and ($c->token_defines_sub($keywords[-1]) or $keywords[-1] eq 'eval');
      33        
1541             }
1542 2317         5298 $stack = undef;
1543             }
1544 27293 100       46724 if ($current_scope & F_STATEMENT_END) {
1545 4463 100 66     10570 if (($current_scope & F_KEEP_TOKENS) and @tokens) {
1546 1022         2235 my $first_token = $tokens[0][0];
1547 1022 100       2461 if ($first_token eq '->') {
1548 46         111 $first_token = $tokens[1][0];
1549             # ignore ->use and ->no
1550             # ->require may be from UNIVERSAL::require
1551 46 100 66     245 if ($first_token eq 'use' or $first_token eq 'no') {
1552 1         2 $first_token = '';
1553             }
1554             }
1555 1022 100       2604 my $cond = (($current_scope | $parent_scope) & (F_CONDITIONAL|F_SIDEFF)) ? 1 : 0;
1556 1022 100       2810 if (exists $c->{callback}{$first_token}) {
1557 758         1992 $c->{current_scope} = \$current_scope;
1558 758         2068 $c->{cond} = $cond;
1559 758         3138 $c->{callback}{$first_token}->($c, $rstr, \@tokens);
1560              
1561 758 50 33     2566 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 1022 100       2923 if (exists $c->{keyword}{$first_token}) {
1569 218         556 $c->{current_scope} = \$current_scope;
1570 218         508 $c->{cond} = $cond;
1571 218         455 $tokens[0][1] = 'KEYWORD';
1572 218         736 $c->run_callback_for(keyword => $first_token, \@tokens);
1573             }
1574 1022 100 66     4941 if (exists $c->{method}{$first_token} and $caller_package) {
1575 18         58 unshift @tokens, [$caller_package, 'WORD'];
1576 18         42 $c->{current_scope} = \$current_scope;
1577 18         39 $c->{cond} = $cond;
1578 18         71 $c->run_callback_for(method => $first_token, \@tokens);
1579             }
1580 1022 100       3913 if ($current_scope & F_SIDEFF) {
1581 11         27 $current_scope &= MASK_SIDEFF;
1582 11         74 while(my $token = shift @tokens) {
1583 58 100       194 last if $has_sideff{$token->[0]};
1584             }
1585 11 100       36 $current_scope &= F_SIDEFF if grep {$has_sideff{$_->[0]}} @tokens;
  46         111  
1586 11 50       35 if (@tokens) {
1587 11         31 $first_token = $tokens[0][0];
1588 11 100       44 $cond = (($current_scope | $parent_scope) & (F_CONDITIONAL|F_SIDEFF)) ? 1 : 0;
1589 11 50       41 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       42 if (exists $c->{keyword}{$first_token}) {
1595 1         3 $c->{current_scope} = \$current_scope;
1596 1         3 $c->{cond} = $cond;
1597 1         2 $tokens[0][1] = 'KEYWORD';
1598 1         5 $c->run_callback_for(keyword => $first_token, \@tokens);
1599             }
1600 11 50 33     96 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 4463         7783 @tokens = ();
1610 4463         6284 @keywords = ();
1611 4463         6276 $current_scope &= MASK_STATEMENT_END;
1612 4463         6275 $caller_package = undef;
1613 4463         7178 $token = $token_type = '';
1614 4463         6088 _debug('END SENTENSE') if DEBUG;
1615             }
1616 27293 100 100     49563 if ($unstack and @{$c->{stack}}) {
  2243         6191  
1617 2221         3246 my $stacked = pop @{$c->{stack}};
  2221         4139  
1618 2221         4684 my $stacked_type = substr($stacked->[0], -1);
1619 2221 50 66     13147 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 2221         3450 _dump_stack($c, $unstack) if DEBUG;
1629 2221         3314 $current_scope |= F_SCOPE_END;
1630 2221         3491 $unstack = undef;
1631             }
1632              
1633 27293 100       47114 last if $current_scope & F_SCOPE_END;
1634 24999 100       44594 last if $c->{ended};
1635 24894 50 33     45729 last if $c->{last_found_by_skimming} and $c->{last_found_by_skimming} < pos($$rstr);
1636              
1637 24894         43750 ($prev_token, $prev_token_type) = ($token, $token_type);
1638             }
1639              
1640 44586 50 33     57004 if (@{$c->{errors}} and !($parent_scope & F_STRING_EVAL)) {
  44586         122024  
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 3158 100       6790 if (@tokens) {
1648 41 50       243 if (my $first_token = $tokens[0][0]) {
1649 41 100       210 if (exists $c->{callback}{$first_token}) {
1650 28         113 $c->{callback}{$first_token}->($c, $rstr, \@tokens);
1651             }
1652 41 100       146 if (exists $c->{keyword}{$first_token}) {
1653 10         28 $tokens[0][1] = 'KEYWORD';
1654 10         42 $c->run_callback_for(keyword => $first_token, \@tokens);
1655             }
1656             }
1657             }
1658              
1659 3158         4575 _dump_stack($c, "END SCOPE") if DEBUG;
1660              
1661 3158         8524 \@scope_tokens;
1662             }
1663              
1664             sub _match_quotelike {
1665 188     188   789 my ($self, $c, $rstr, $op) = @_;
1666              
1667             # '#' only works when it comes just after the op,
1668             # without prepending spaces
1669 188         1927 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1670              
1671 188 50       828 unless ($$rstr =~ m/\G(\S)/gc) {
1672 0         0 return _match_error($rstr, "No block delimiter found after $op");
1673             }
1674 188         448 my $ldel = $1;
1675 188         371 my $startpos = pos($$rstr);
1676              
1677 188 100       602 if ($ldel =~ /[[(<{]/) {
1678 135         378 my ($rdel, $re_skip) = _gen_rdel_and_re_skip($ldel);
1679 135         349 my @nest = ($ldel);
1680 135         249 my ($p, $c1);
1681 135         375 while(defined($p = pos($$rstr))) {
1682 360         708 $c1 = substr($$rstr, $p, 1);
1683 360 100       733 if ($c1 eq '\\') {
1684 28         65 pos($$rstr) = $p + 2;
1685 28         63 next;
1686             }
1687 332 100       767 if ($c1 eq $ldel) {
1688 15         33 pos($$rstr) = $p + 1;
1689 15         30 push @nest, $ldel;
1690 15         30 next;
1691             }
1692 317 100       651 if ($c1 eq $rdel) {
1693 150         357 pos($$rstr) = $p + 1;
1694 150         293 pop @nest;
1695 150 100       467 last unless @nest;
1696 15         35 next;
1697             }
1698 167 50       1813 $$rstr =~ m{\G$re_skip}gc and next;
1699 0         0 last;
1700             }
1701 135 50       448 return if @nest;
1702             } else {
1703 53         172 my $re = _gen_re_str_in_delims_with_end_delim($ldel);
1704 53 50       850 $$rstr =~ /\G$re/gcs or return;
1705             }
1706              
1707 188         449 my $endpos = pos($$rstr);
1708              
1709 188         1130 return [substr($$rstr, $startpos, $endpos - $startpos - 1), $op];
1710             }
1711              
1712             sub _match_regexp0 { # //
1713 98     98   274 my ($self, $c, $rstr, $startpos, $token_type) = @_;
1714 98         234 pos($$rstr) = $startpos + 1;
1715              
1716 98         279 my $re_shortcut = _gen_re_regexp_shortcut('/');
1717 98 100 100     1244 $$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         313 $$rstr =~ m/\G([msixpodualgc]*)/gc;
1721 97         215 my $mod = $1;
1722              
1723 97         160 my $endpos = pos($$rstr);
1724              
1725 97         273 my $re = substr($$rstr, $startpos, $endpos - $startpos);
1726 97 100 100     320 if ($re =~ /\n/s and $mod !~ /x/) {
1727 1         6 return _match_error($rstr, "multiline without x");
1728             }
1729 96         337 return $re;
1730             }
1731              
1732             sub _match_regexp {
1733 47     47   181 my ($self, $c, $rstr) = @_;
1734 47   50     202 my $startpos = pos($$rstr) || 0;
1735              
1736             # '#' only works when it comes just after the op,
1737             # without prepending spaces
1738 47         469 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1739              
1740 47 50       185 unless ($$rstr =~ m/\G(\S)/gc) {
1741 0         0 return _match_error($rstr, "No block delimiter found");
1742             }
1743 47         161 my ($ldel, $rdel) = ($1, $1);
1744              
1745 47 100       155 if ($ldel =~ /[[(<{]/) {
1746 27         64 $rdel =~ tr/[({/;
1747             }
1748              
1749 47         210 my $re_shortcut = _gen_re_regexp_shortcut($ldel, $rdel);
1750 47 50 66     1173 $$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         181 $$rstr =~ m/\G[msixpodualgc]*/gc;
1755 47         96 my $endpos = pos($$rstr);
1756              
1757 47         201 return substr($$rstr, $startpos, $endpos - $startpos);
1758             }
1759              
1760             sub _match_substitute {
1761 53     53   131 my ($self, $c, $rstr) = @_;
1762 53   50     152 my $startpos = pos($$rstr) || 0;
1763              
1764             # '#' only works when it comes just after the op,
1765             # without prepending spaces
1766 53         544 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1767              
1768 53 50       226 unless ($$rstr =~ m/\G(\S)/gc) {
1769 0         0 return _match_error($rstr, "No block delimiter found");
1770             }
1771 53         164 my ($ldel1, $rdel1) = ($1, $1);
1772              
1773 53 100       160 if ($ldel1 =~ /[[(<{]/) {
1774 22         44 $rdel1 =~ tr/[({/;
1775             }
1776              
1777 53         142 my $re_shortcut = _gen_re_regexp_shortcut($ldel1, $rdel1);
1778 53 50 100     1161 ($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       221 defined($self->_scan_re2($c, $rstr, $ldel1, 's')) or return;
1781 53         146 $$rstr =~ m/\G[msixpodualgcer]*/gc;
1782 53         97 my $endpos = pos($$rstr);
1783              
1784 53         203 return substr($$rstr, $startpos, $endpos - $startpos);
1785             }
1786              
1787             sub _match_transliterate {
1788 5     5   16 my ($self, $c, $rstr) = @_;
1789 5   50     19 my $startpos = pos($$rstr) || 0;
1790              
1791             # '#' only works when it comes just after the op,
1792             # without prepending spaces
1793 5         95 $$rstr =~ m/\G(?:\s(?:$re_comment))?\s*/gcs;
1794              
1795 5 50       25 unless ($$rstr =~ m/\G(\S)/gc) {
1796 0         0 return _match_error($rstr, "No block delimiter found");
1797             }
1798 5         15 my $ldel1 = $1;
1799 5         10 my $ldel2;
1800              
1801 5 100       20 if ($ldel1 =~ /[[(<{]/) {
1802 1         4 (my $rdel1 = $ldel1) =~ tr/[({/;
1803 1         4 my $re = _gen_re_str_in_delims_with_end_delim($rdel1);
1804 1 50       22 $$rstr =~ /\G$re/gcs or return;
1805 1         35 $$rstr =~ /\G(?:$re_comment)/gcs;
1806 1 50       8 unless ($$rstr =~ /\G\s*(\S)/gc) {
1807 0         0 return _match_error($rstr, "Missing second block");
1808             }
1809 1         5 $ldel2 = $1;
1810             } else {
1811 4         14 my $re = _gen_re_str_in_delims_with_end_delim($ldel1);
1812 4 50       101 $$rstr =~ /\G$re/gcs or return;
1813 4         15 $ldel2 = $ldel1;
1814             }
1815              
1816 5 100       30 if ($ldel2 =~ /[[(<{]/) {
1817 1         4 (my $rdel2 = $ldel2) =~ tr/[({/;
1818 1         4 my $re = _gen_re_str_in_delims_with_end_delim($rdel2);
1819 1 50       33 $$rstr =~ /\G$re/gcs or return;
1820             } else {
1821 4         22 my $re = _gen_re_str_in_delims_with_end_delim($ldel2);
1822 4 50       74 $$rstr =~ /\G$re/gcs or return;
1823             }
1824              
1825 5         21 $$rstr =~ m/\G[cdsr]*/gc;
1826 5         13 my $endpos = pos($$rstr);
1827              
1828 5         30 return substr($$rstr, $startpos, $endpos - $startpos);
1829             }
1830              
1831             sub _match_heredoc {
1832 16     16   49 my ($self, $c, $rstr) = @_;
1833              
1834 16   50     47 my $startpos = pos($$rstr) || 0;
1835              
1836 16         72 $$rstr =~ m{\G(?:<<(~)?\s*)}gc;
1837 16 100       114 my $indent = $1 ? "\\s*" : "";
1838              
1839 16         29 my $label;
1840 16 100       427 if ($$rstr =~ m{\G\\?([A-Za-z_]\w*)}gc) {
    50          
1841 8         20 $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         36 $label = $+;
1848             } else {
1849 0         0 return;
1850             }
1851 16         52 $label =~ s/\\(.)/$1/g;
1852 16         34 my $extrapos = pos($$rstr);
1853 16         71 $$rstr =~ m{\G.*\n}gc;
1854 16         49 my $str1pos = pos($$rstr)--;
1855 16 100       494 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         57 my $ldpos = pos($$rstr);
1859 14         1070 $$rstr =~ m{\G\Q$label\E\n}gc;
1860 14         52 my $ld2pos = pos($$rstr);
1861              
1862 14         89 my $heredoc = [
1863             substr($$rstr, $str1pos, $ldpos-$str1pos),
1864             substr($$rstr, $startpos, $extrapos-$startpos),
1865             substr($$rstr, $ldpos, $ld2pos-$ldpos),
1866             ];
1867 14         128 substr($$rstr, $str1pos, $ld2pos - $str1pos) = '';
1868 14         109 pos($$rstr) = $extrapos;
1869 14 100       57 if ($indent) {
1870 1         5 $c->add_perl('5.026', '<<~');
1871             }
1872 14         67 return $heredoc;
1873             }
1874              
1875             sub _scan_re {
1876 126     126   445 my ($self, $c, $rstr, $ldel, $rdel, $op) = @_;
1877 126   50     342 my $startpos = pos($$rstr) || 0;
1878              
1879 126         181 _debug(" L $ldel R $rdel") if DEBUG_RE;
1880              
1881 126         207 my ($outer_opening_delimiter, $outer_closing_delimiter);
1882 126 100       251 if (@{$c->{stack}}) {
  126         374  
1883 110         310 ($outer_closing_delimiter = $outer_opening_delimiter = $c->{stack}[-1][0]) =~ tr/[({/;
1884             }
1885              
1886 126         333 my @nesting = ($ldel);
1887 126         204 my $multiline = 0;
1888 126         182 my $saw_sharp = 0;
1889 126         179 my $prev;
1890 126         193 my ($p, $c1);
1891 126         307 while (defined($p = pos($$rstr))) {
1892 5053         7572 $c1 = substr($$rstr, $p, 1);
1893 5053 100       8246 if ($c1 eq "\n") {
1894 271         637 $$rstr =~ m{\G\n\s*}gcs;
1895 271         388 $multiline = 1;
1896 271         347 $saw_sharp = 0;
1897             # _debug("CRLF") if DEBUG_RE;
1898 271         521 next;
1899             }
1900 4782 100 66     11590 if ($c1 eq ' ' or $c1 eq "\t") {
1901 696         1271 $$rstr =~ m{\G\s*}gc;
1902             # _debug("WHITESPACE") if DEBUG_RE;
1903 696         1244 next;
1904             }
1905 4086 100 100     6913 if ($c1 eq '#' and $rdel ne '#') {
1906 144 100 100     821 if ($multiline and $$rstr =~ m{\G(#[^\Q$rdel\E]*?)\n}gcs) {
1907 94         161 _debug(" comment $1") if DEBUG_RE
1908             } else {
1909 50         104 pos($$rstr) = $p + 1;
1910 50         94 $saw_sharp = 1;
1911 50         70 _debug(" saw #") if DEBUG_RE;
1912             }
1913 144         302 next;
1914             }
1915              
1916 3942 100 100     6880 if ($c1 eq '\\' and $rdel ne '\\') {
1917 416 50       1029 if ($$rstr =~ m/\G(\\.)/gcs) {
1918 416         527 _debug(" escaped $1") if DEBUG_RE;
1919 416         805 next;
1920             }
1921             }
1922              
1923 3526         4157 _debug(" looking @nesting: $c1") if DEBUG_RE;
1924              
1925 3526 100       5449 if ($c1 eq '[') {
1926             # character class may have other (ignorable) delimiters
1927 197 50       515 if ($$rstr =~ m/\G(\[\[:\w+?:\]\])/gcs) {
1928 0         0 _debug(" character class $1") if DEBUG_RE;
1929 0         0 next;
1930             }
1931 197 100       619 if ($$rstr =~ m/\G(\[[^\\\]]]*?(\\.[^\\\]]]*)*\])/gcs) {
1932 59         71 _debug(" character class: $1") if DEBUG_RE;
1933 59         120 next;
1934             }
1935             }
1936              
1937 3467 100       6382 if ($c1 eq $rdel) {
    100          
1938 156         334 pos($$rstr) = $p + 1;
1939 156 100       377 if ($saw_sharp) {
1940 39         60 my $tmp_pos = $p + 1;
1941 39 100       71 if ($op eq 's') {
1942 3         5 _debug(" looking for latter part") if DEBUG_RE;
1943 3         9 my $latter = $self->_scan_re2($c, $rstr, $ldel, $op);
1944 3 50       25 if (!defined $latter) {
1945 0         0 pos($$rstr) = $tmp_pos;
1946 0         0 next;
1947             }
1948 3         6 _debug(" latter: $latter") if DEBUG_RE;
1949             }
1950 39 100       125 if ($$rstr =~ m/\G[a-wyz]*x/) {
1951             # looks like an end of block
1952 2         4 _debug(" end of block $rdel (after #)") if DEBUG_RE;
1953 2         6 @nesting = ();
1954 2         5 pos($$rstr) = $tmp_pos;
1955 2         5 last;
1956             }
1957 37         101 pos($$rstr) = $tmp_pos;
1958 37 100       110 if ($multiline) {
1959 29         263 next; # part of a comment
1960             }
1961             }
1962 125         175 _debug(" end of block $rdel") if DEBUG_RE;
1963 125         233 my $expected = $rdel;
1964 125 100       244 if ($ldel ne $rdel) {
1965 44         81 $expected =~ tr/)}]>/({[
1966             }
1967 125         1252 while(my $nested = pop @nesting) {
1968 129 100       320 last if $nested eq $expected;
1969             }
1970 125 100       283 last unless @nesting;
1971 2         5 next;
1972             } elsif ($c1 eq $ldel) {
1973 30         57 pos($$rstr) = $p + 1;
1974 30 100 66     87 if ($multiline and $saw_sharp) {
1975             } else {
1976 2         4 _debug(" block $ldel") if DEBUG_RE;
1977 2         5 push @nesting, $ldel;
1978 2         5 next;
1979             }
1980             }
1981              
1982 3309 100       5375 if ($c1 eq '{') {
1983             # quantifier shouldn't be nested
1984 45 100       134 if ($$rstr =~ m/\G(\{[0-9]+(?:,(?:[0-9]+)?)?})/gcs) {
1985 4         7 _debug(" quantifier $1") if DEBUG_RE;
1986 4         8 next;
1987             }
1988             }
1989              
1990 3305 100       5246 if ($c1 eq '(') {
1991 407         728 my $c2 = substr($$rstr, $p + 1, 1);
1992 407 100 100     1309 if ($c2 eq '?' and !($multiline and $saw_sharp)) {
      100        
1993             # code
1994 209 100       694 if ($$rstr =~ m/\G((\()\?+?)(?=\{)/gc) {
1995 70         111 _debug(" code $1") if DEBUG_RE;
1996 70         166 push @nesting, $2;
1997 70 50       118 unless (eval { $self->_scan($c, $rstr, F_EXPECTS_BRACKET); 1 }) {
  70         233  
  70         174  
1998 0         0 _debug("scan failed") if DEBUG_RE;
1999 0         0 return;
2000             }
2001 70         192 next;
2002             }
2003             # comment
2004 139 100       304 if ($$rstr =~ m{\G(\(\?\#[^\\\)]*(?:\\.[^\\\)]*)*\))}gcs) {
2005 10         14 _debug(" comment $1") if DEBUG_RE;
2006 10         17 next;
2007             }
2008             }
2009              
2010             # grouping may have (ignorable) <>
2011 327 50       1029 if ($$rstr =~ m/\G((\()(?:<[!=]|<\w+?>|>)?)/gc) {
2012 327         453 _debug(" group $1") if DEBUG_RE;
2013 327         806 push @nesting, $2;
2014 327         643 next;
2015             }
2016             }
2017              
2018             # maybe variables (maybe not)
2019 2898 100 100     5160 if ($c1 eq '$' and substr($$rstr, $p + 1, 1) eq '{') {
2020 3         7 my @tmp_stack = @{$c->{stack}};
  3         9  
2021 3 50       7 next if eval { $self->_scan($c, $rstr, F_EXPECTS_BRACKET); 1 };
  3         10  
  3         11  
2022 0         0 pos($$rstr) = $p;
2023 0         0 $c->{stack} = \@tmp_stack;
2024             }
2025              
2026 2895 100       4485 if ($c1 eq ')') {
2027 397 100 66     1248 if (@nesting and $nesting[-1] eq '(') {
2028 393         524 _debug(" end of group $c1") if DEBUG_RE;
2029 393         515 pop @nesting;
2030 393         888 pos($$rstr) = $p + 1;
2031 393         893 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       3812 if (!$op) {
2039 87 100 66     1121 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     180 if ($outer_closing_delimiter and $c1 eq $outer_closing_delimiter) {
2046 2 100 66     8 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       5620 if ($$rstr =~ m/\G(\w+|.)/gcs) {
2057 2499         3111 _debug(" rest $1") if DEBUG_RE;
2058 2499         4388 next;
2059             }
2060 0         0 last;
2061             }
2062 125 50       386 if ($#nesting>=0) {
2063 0         0 return _match_error($rstr, "Unmatched opening bracket(s): ". join("..",@nesting)."..");
2064             }
2065              
2066 125         203 my $endpos = pos($$rstr);
2067              
2068 125         652 return substr($$rstr, $startpos, $endpos - $startpos);
2069             }
2070              
2071              
2072             sub _scan_re2 {
2073 56     56   159 my ($self, $c, $rstr, $ldel, $op) = @_;
2074 56         114 my $startpos = pos($$rstr);
2075              
2076 56 100       175 if ($ldel =~ /[[(<{]/) {
2077 23         152 $$rstr =~ /\G(?:$re_comment)/gcs;
2078              
2079 23 50       90 unless ($$rstr =~ /\G\s*(\S)/gc) {
2080 0         0 return _match_error($rstr, "Missing second block for quotelike $op");
2081             }
2082 23         58 $ldel = $1;
2083             }
2084              
2085 56 100       167 if ($ldel =~ /[[(<{]/) {
2086 23         52 my ($rdel, $re_skip) = _gen_rdel_and_re_skip($ldel);
2087 23         53 my @nest = $ldel;
2088 23         35 my ($p, $c1);
2089 23         55 while(defined($p = pos($$rstr))) {
2090 168         257 $c1 = substr($$rstr, $p, 1);
2091 168 100       271 if ($c1 eq '\\') {
2092 16         30 pos($$rstr) = $p + 2;
2093 16         31 next;
2094             }
2095 152 100       230 if ($c1 eq $ldel) {
2096 25         45 pos($$rstr) = $p + 1;
2097 25         37 push @nest, $ldel;
2098 25         45 next;
2099             }
2100 127 100       199 if ($c1 eq $rdel) {
2101 48         86 pos($$rstr) = $p + 1;
2102 48         79 pop @nest;
2103 48 100       107 last unless @nest;
2104 25         42 next;
2105             }
2106 79 50       365 $$rstr =~ m{\G$re_skip}gc and next;
2107 0         0 last;
2108             }
2109 23 50       58 return _match_error($rstr, "nesting mismatch: @nest") if @nest;
2110             } else {
2111 33         116 my $re = _gen_re_str_in_delims_with_end_delim($ldel);
2112 33 50       420 $$rstr =~ /\G$re/gcs or return;
2113             }
2114              
2115 56         126 my $endpos = pos($$rstr);
2116              
2117 56         199 return substr($$rstr, $startpos, $endpos - $startpos);
2118             }
2119              
2120             sub _use {
2121 686     686   1602 my ($c, $rstr, $tokens) = @_;
2122 686         1120 _debug("USE TOKENS: ".(Data::Dump::dump($tokens))) if DEBUG;
2123 686         1298 shift @$tokens; # discard 'use' itself
2124              
2125             # TODO: see if the token is WORD or not?
2126 686 50       2184 my $name_token = shift @$tokens or return;
2127 686         1578 my $name = $name_token->[0];
2128 686 50 33     3747 return if !defined $name or ref $name or $name eq '';
      33        
2129              
2130 686         1618 my $c1 = substr($name, 0, 1);
2131 686 100       1669 if ($c1 eq '5') {
2132 3         19 $c->add(perl => $name);
2133 3         316 return;
2134             }
2135 683 100       1678 if ($c1 eq 'v') {
2136 6         29 my $c2 = substr($name, 1, 1);
2137 6 100       22 if ($c2 eq '5') {
2138 1         4 $c->add(perl => $name);
2139 1         101 return;
2140             }
2141 5 50       28 if ($c2 eq '6') {
2142 0         0 $c->{perl6} = 1;
2143 0         0 $c->{ended} = 1;
2144 0         0 return;
2145             }
2146             }
2147 682 100       2267 if ($c->enables_utf8($name)) {
2148 18         69 $c->add($name => 0);
2149 18         514 $c->{utf8} = 1;
2150 18 100       62 if (!$c->{decoded}) {
2151 9         23 $c->{decoded} = 1;
2152 9         12 _debug("UTF8 IS ON") if DEBUG;
2153 9         143 utf8::decode($$rstr);
2154 9         95 pos($$rstr) = 0;
2155 9         31 $c->{ended} = $c->{redo} = 1;
2156             }
2157             }
2158              
2159 682 50       2501 if (is_module_name($name)) {
2160 682         1615 my $maybe_version_token = $tokens->[0];
2161 682         1266 my $maybe_version_token_desc = $maybe_version_token->[1];
2162 682 100 66     3441 if ($maybe_version_token_desc and ($maybe_version_token_desc eq 'NUMBER' or $maybe_version_token_desc eq 'VERSION_STRING')) {
      100        
2163 34         149 $c->add($name => $maybe_version_token->[0]);
2164 34         3604 shift @$tokens;
2165             } else {
2166 648         2252 $c->add($name => 0);
2167             }
2168              
2169 682 100       27865 if (exists $sub_keywords{$name}) {
2170 5         10 $c->register_sub_keywords(@{$sub_keywords{$name}});
  5         37  
2171 5         26 $c->prototype_re(qr{\G(\((?:[^\\\(\)]*(?:\\.[^\\\(\)]*)*)\))});
2172             }
2173 682 100       2086 if (exists $filter_modules{$name}) {
2174 1         2 my $tmp = pos($$rstr);
2175 1         3 my $redo = $filter_modules{$name}->($rstr);
2176 1         2 pos($$rstr) = $tmp;
2177 1 50       9 $c->{ended} = $c->{redo} = 1 if $redo;
2178             }
2179             }
2180              
2181 682 100       2220 if ($c->has_callback_for(use => $name)) {
    100          
2182 349         752 eval { $c->run_callback_for(use => $name, $tokens) };
  349         1063  
2183 349 50       2634 warn "Callback Error: $@" if $@;
2184             } elsif ($name =~ /\b(?:Mo[ou]se?X?|MooX?|Elk|Antlers|Role)\b/) {
2185 2 50       14 my $module = $name =~ /Role/ ? 'Moose::Role' : 'Moose';
2186 2 100       10 if ($c->has_callback_for(use => $module)) {
2187 1         3 eval { $c->run_callback_for(use => $module, $tokens) };
  1         6  
2188 1 50       5 warn "Callback Error: $@" if $@;
2189             }
2190             }
2191              
2192 682 50       2605 if (exists $unsupported_packages{$name}) {
2193 0         0 $c->{found_unsupported_package} = $name;
2194             }
2195             }
2196              
2197             sub _require {
2198 69     69   196 my ($c, $rstr, $tokens) = @_;
2199 69         106 _debug("REQUIRE TOKENS: ".(Data::Dump::dump($tokens))) if DEBUG;
2200 69         144 shift @$tokens; # discard 'require' itself
2201              
2202             # TODO: see if the token is WORD or not?
2203 69 50       227 my $name_token = shift @$tokens or return;
2204 69         149 my $name = $name_token->[0];
2205 69 100       203 if (ref $name) {
2206 7         19 $name = $name->[0];
2207 7 100       77 return if $name =~ /\.pl$/i;
2208              
2209 5         28 $name =~ s|/|::|g;
2210 5         22 $name =~ s|\.pm$||i;
2211             }
2212 67 50 33     309 return if !defined $name or $name eq '';
2213              
2214 67         171 my $c1 = substr($name, 0, 1);
2215 67 100       193 if ($c1 eq '5') {
2216 1         5 $c->add_conditional(perl => $name);
2217 1         99 return;
2218             }
2219 66 100       198 if ($c1 eq 'v') {
2220 1         3 my $c2 = substr($name, 1, 1);
2221 1 50       4 if ($c2 eq '5') {
2222 1         4 $c->add_conditional(perl => $name);
2223 1         126 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       266 if (is_module_name($name)) {
2232 62         282 $c->add_conditional($name => 0);
2233 62         2187 return;
2234             }
2235             }
2236              
2237             sub _no {
2238 31     31   84 my ($c, $rstr, $tokens) = @_;
2239 31         53 _debug("NO TOKENS: ".(Data::Dump::dump($tokens))) if DEBUG;
2240 31         65 shift @$tokens; # discard 'no' itself
2241              
2242             # TODO: see if the token is WORD or not?
2243 31 50       106 my $name_token = shift @$tokens or return;
2244 31         90 my $name = $name_token->[0];
2245 31 50 33     228 return if !defined $name or ref $name or $name eq '';
      33        
2246              
2247 31         88 my $c1 = substr($name, 0, 1);
2248 31 100       91 if ($c1 eq '5') {
2249 1         6 $c->add_no(perl => $name);
2250 1         108 return;
2251             }
2252 30 100       89 if ($c1 eq 'v') {
2253 1         3 my $c2 = substr($name, 1, 1);
2254 1 50       5 if ($c2 eq '5') {
2255 1         6 $c->add_no(perl => $name);
2256 1         129 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       77 if ($name eq 'utf8') {
2265 0         0 $c->{utf8} = 0;
2266             }
2267              
2268 29 50       125 if (is_module_name($name)) {
2269 29         72 my $maybe_version_token = $tokens->[0];
2270 29         56 my $maybe_version_token_desc = $maybe_version_token->[1];
2271 29 100 66     210 if ($maybe_version_token_desc and ($maybe_version_token_desc eq 'NUMBER' or $maybe_version_token_desc eq 'VERSION_STRING')) {
      66        
2272 3         15 $c->add_no($name => $maybe_version_token->[0]);
2273 3         329 shift @$tokens;
2274             } else {
2275 26         114 $c->add_no($name => 0);
2276             }
2277             }
2278              
2279 29 100       1022 if ($c->has_callback_for(no => $name)) {
2280 2         3 eval { $c->run_callback_for(no => $name, $tokens) };
  2         7  
2281 2 50       7 warn "Callback Error: $@" if $@;
2282 2         4 return;
2283             }
2284             }
2285              
2286             1;
2287              
2288             __END__