File Coverage

lib/Perl/PrereqScanner/NotQuiteLite/Parser/Core.pm
Criterion Covered Total %
statement 122 140 87.1
branch 68 88 77.2
condition 46 73 63.0
subroutine 13 14 92.8
pod 0 11 0.0
total 249 326 76.3


line stmt bran cond sub pod time code
1             package Perl::PrereqScanner::NotQuiteLite::Parser::Core;
2              
3 97     97   1875 use strict;
  97         202  
  97         2919  
4 97     97   417 use warnings;
  97         163  
  97         3592  
5 97     97   366 use Perl::PrereqScanner::NotQuiteLite::Util;
  97         202  
  97         177418  
6              
7             my %feature_since = (
8             say => '5.010',
9             state => '5.010',
10             switch => '5.010',
11             unicode_strings => '5.012',
12             current_sub => '5.016',
13             evalbytes => '5.016',
14             fc => '5.016',
15             arybase => '5.016', # removed
16             unicode_eval => '5.016',
17             lexical_subs => '5.018',
18             postderef => '5.020',
19             postderef_qq => '5.020',
20             signatures => '5.020',
21             bitwise => '5.022',
22             refaliasing => '5.022',
23             declared_refs => '5.026',
24             indirect => '5.032',
25             isa => '5.032',
26             multidimensional => '5.034',
27             bareword_filehandles => '5.034',
28             try => '5.034',
29             defer => '5.036',
30             extra_paired_delimiters => '5.036',
31             class => '5.038',
32             module_true => '5.038',
33             );
34              
35             my %builtin_since = (
36             true => '5.036',
37             false => '5.036',
38             inf => '5.040',
39             nan => '5.040',
40              
41             is_bool => '5.036',
42             weaken => '5.036',
43             unweaken => '5.036',
44             is_weak => '5.036',
45             blessed => '5.036',
46             refaddr => '5.036',
47             reftype => '5.036',
48             ceil => '5.036',
49             floor => '5.036',
50             is_tainted => '5.038',
51             trim => '5.036',
52             stringify => '5.040',
53              
54             created_as_string => '5.036',
55             created_as_number => '5.036',
56              
57             load_module => '5.040',
58              
59             indexed => '5.036',
60             export_lexically => '5.038',
61             );
62              
63             sub register { return {
64 96     96 0 1003 use => {
65             if => 'parse_if_args',
66             base => 'parse_base_args',
67             parent => 'parse_parent_args',
68             feature => 'parse_feature_args',
69             experimental => 'parse_feature_args',
70             builtin => 'parse_builtin_args',
71             },
72             keyword => {
73             package => 'parse_package',
74             exit => 'parse_begin_exit',
75             },
76             }}
77              
78             sub parse_if_args {
79 9     9 0 19 my ($class, $c, $used_module, $raw_tokens) = @_;
80              
81 9         21 while(my $token = shift @$raw_tokens) {
82 20 100       62 last if $token->[1] eq 'COMMA';
83             }
84              
85 9         27 my $tokens = convert_string_tokens($raw_tokens);
86 9         15 my $module = shift @$tokens;
87 9 50 66     27 if (ref $module and ($module->[1] eq 'WORD' or $module->[1] eq 'KEYWORD')) {
      66        
88 4         19 $module = $module->[0];
89             }
90 9 50       20 if (is_module_name($module)) {
91 9 50       20 if (is_version($tokens->[0])) {
92 0         0 my $version = shift @$tokens;
93 0         0 $c->add_recommendation($module => $version);
94             } else {
95 9         28 $c->add_recommendation($module => 0);
96             }
97             } else {
98 0         0 push @{$c->{errors}}, "use if module not found";
  0         0  
99             }
100             }
101              
102             sub parse_base_args {
103 25     25 0 56 my ($class, $c, $used_module, $raw_tokens) = @_;
104              
105 25         121 my $tokens = convert_string_tokens($raw_tokens);
106 25 50       65 if (is_version($tokens->[0])) {
107 0         0 $c->add($used_module => shift @$tokens);
108             }
109 25         67 while(my $token = shift @$tokens) {
110 59         1045 my $module = $token;
111 59 100 100     196 if (ref $module and ($module->[1] || '') eq 'WORD') {
      100        
112             # allow bareword, but disallow function()
113 2         4 $module = $module->[0];
114 2 100 33     13 next if @$tokens and ref $tokens->[0] and ($tokens->[0][1] || '') eq '()';
      50        
      66        
115             }
116             # bareword in parentheses
117 58 100 100     147 if (ref $module and ref $module->[0]) {
118 3         6 $module = $module->[0][0];
119             }
120 58 100       133 if (is_module_name($module)) {
121 29         101 $c->add($module => 0);
122             }
123             }
124             }
125              
126             sub parse_parent_args {
127 28     28 0 56 my ($class, $c, $used_module, $raw_tokens) = @_;
128              
129 28         71 my $tokens = convert_string_tokens($raw_tokens);
130 28 50       69 if (is_version($tokens->[0])) {
131 0         0 $c->add($used_module => shift @$tokens);
132             }
133 28         70 while(my $token = shift @$tokens) {
134 54 100       760 last if $token eq '-norequire';
135 52         67 my $module = $token;
136 52 100       91 if (ref $token) {
137 31 100       80 last if $token->[0] eq '-norequire';
138             }
139 47 100 100     122 if (ref $module and ($module->[1] || '') eq 'WORD') {
      100        
140             # allow bareword, but disallow function()
141 2         5 $module = $module->[0];
142 2 100 33     14 next if @$tokens and ref $tokens->[0] and ($tokens->[0][1] || '') eq '()';
      50        
      66        
143             }
144             # bareword in parentheses
145 46 100 100     103 if (ref $module and ref $module->[0]) {
146 3         5 $module = $module->[0][0];
147             }
148 46 100       76 $c->add($module => 0) if is_module_name($module);
149             }
150             }
151              
152             sub parse_feature_args {
153 54     54 0 148 my ($class, $c, $used_module, $raw_tokens) = @_;
154              
155 54 100       145 if ($used_module eq 'feature') {
    50          
156 38         81 $c->add_perl('5.010', 'feature');
157             } elsif ($used_module eq 'experimental') {
158 16         50 $c->add_perl('5.020', 'experimental');
159             }
160 54         156 my $tokens = convert_string_tokens($raw_tokens);
161 54 50       137 if (is_version($tokens->[0])) {
162 0         0 $c->add($used_module => shift @$tokens);
163             }
164 54         147 while(my $token = shift @$tokens) {
165 108 100       360 next if ref $token;
166 51         173 $c->{feature}{$token} = 1;
167 51 100       125 if ($token eq 'class') {
168 10         32 $class->register_class($c, $used_module);
169             }
170 51 100       128 if (exists $feature_since{$token}) {
171 47         207 $c->add_perl($feature_since{$token} => "feature $token");
172 47         150 next;
173             }
174 4 50       18 if ($token =~ /^:5\.([0-9]+)(\.\[0-9]+)?/) {
175 4         21 my $version = sprintf '5.%03d', $1;
176 4         12 $c->add_perl($version, $token);
177 4         15 next;
178             }
179             }
180             }
181              
182             sub parse_builtin_args {
183 5     5 0 11 my ($class, $c, $used_module, $raw_tokens) = @_;
184              
185 5         27 my $tokens = convert_string_tokens($raw_tokens);
186 5 50       25 if (is_version($tokens->[0])) {
187 0         0 $c->add($used_module => shift @$tokens);
188             }
189 5         16 while(my $token = shift @$tokens) {
190 10 100       37 next if ref $token;
191 4         24 $c->{builtin}{$token} = 1;
192 4 50       13 if (exists $builtin_since{$token}) {
193 4         22 $c->add_perl($builtin_since{$token} => "builtin $token");
194 4         11 next;
195             }
196             }
197             }
198              
199             sub parse_begin_exit {
200 8     8 0 19 my ($class, $c, $raw_tokens) = @_;
201              
202 8 50       10 my @stack = @{$c->{stack} || []};
  8         29  
203 8 50       21 if (grep {$_->[0] eq '{' and $_->[2] eq 'BEGIN'} @stack) {
  7 100       35  
204 4 100       8 if (grep {$c->token_is_conditional($_->[0])} @$raw_tokens) {
  12 100       45  
205 1         5 $c->{force_cond} = 1;
206 4 50       12 } elsif (grep {$_->[0] eq '{' and $c->token_is_conditional($_->[2])} @stack) {
207 1         4 $c->{force_cond} = 1;
208             } else {
209 2         4 $c->{ended} = 1;
210 2         6 @{$c->{stack}} = ();
  2         9  
211             }
212             }
213             }
214              
215             sub parse_package {
216 32     32 0 74 my ($class, $c, $raw_tokens) = @_;
217              
218 32         117 my $tokens = convert_string_tokens($raw_tokens);
219 32         56 shift @$tokens; # drop "package"
220 32         56 my $token = shift @$tokens;
221 32 100 33     214 if (ref $token && $token->[1] && $token->[1] eq 'WORD') {
      66        
222 31         101 $c->add_package($token->[0]);
223             }
224 32 50       87 if (@$tokens) {
225 32         60 $token = shift @$tokens;
226 32 100       96 if (is_version($token)) {
227 5         15 $c->add_perl("5.012", "package PACKAGE VERSION");
228 5         11 $token = shift @$tokens;
229             }
230 32 100 33     311 if (ref $token && $token->[1] && $token->[1] =~ /^\{/) {
      66        
231 6         16 $c->add_perl("5.014", "package PACKAGE (VERSION) {}");
232             }
233             }
234             }
235              
236             sub register_class {
237 10     10 0 22 my ($class, $c, $used_module) = @_;
238              
239 10         42 $c->register_sub_parser(
240             'class',
241             [$class, 'parse_class_args', $used_module],
242             );
243             # not implemented yet
244             # $c->register_sub_parser(
245             # 'role',
246             # [$class, 'parse_role_args', $used_module],
247             # );
248              
249 10         41 $c->register_keyword_parser(
250             'class',
251             [$class, 'parse_class_args', $used_module],
252             );
253             # not implemented yet
254             # $c->register_keyword_parser(
255             # 'role',
256             # [$class, 'parse_role_args', $used_module],
257             # );
258              
259             # role is not implemented yet
260 10         35 $c->register_sub_keywords(qw/
261             class method
262             /);
263              
264 10         50 $c->prototype_re(qr{\G(\((?:[^\\\(\)]*(?:\\.[^\\\(\)]*)*)\))});
265             }
266              
267             sub parse_class_args {
268 10     10 0 25 my ($class, $c, $used_module, $raw_tokens) = @_;
269              
270 10         25 my $tokens = convert_string_tokens($raw_tokens);
271 10         19 shift @$tokens; # discard class
272              
273 10         18 my $isa = my $does = 0;
274 10         23 while(my $token = shift @$tokens) {
275 22         319 my ($name, $version) = ('', 0);
276 22 100 33     113 if (ref $token && $token->[1] && $token->[1] eq 'WORD') {
      66        
277 10 50       28 if (is_module_name($token->[0])) {
278 10         16 $name = $token->[0];
279 10 100 100     47 if (@$tokens && is_version($tokens->[0])) {
280 5         9 $version = shift @$tokens;
281             }
282 10         49 $c->add_package($name => $version);
283             }
284             }
285 22 100 33     162 if (ref $token && $token->[1] && $token->[1] eq 'ATTRIBUTE') {
      66        
286 8         53 while($token->[0] =~ s/:(?:isa|does)\(([^)]+)\)//) {
287 8         30 my ($name, $version) = split /\s+/, $1;
288 8   100     29 $version ||= 0;
289 8 50 33     13 if (is_module_name($name) && is_version($version)) {
290 8         19 $c->add($name => $version);
291             }
292             }
293             }
294             }
295             }
296              
297             sub parse_role_args {
298 0     0 0   my ($class, $c, $used_module, $raw_tokens) = @_;
299              
300 0           my $tokens = convert_string_tokens($raw_tokens);
301 0           shift @$tokens; # discard role
302              
303 0           while(my $token = shift @$tokens) {
304 0           my ($name, $version) = ('', 0);
305 0 0         if (is_module_name($token->[0])) {
306 0           $name = $token->[0];
307 0 0 0       if (@$tokens && is_version($tokens->[0])) {
308 0           $version = shift @$tokens;
309             }
310 0           $c->add_package($name => $version);
311             }
312             }
313             }
314              
315             1;
316              
317             __END__