line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Code::ART; |
2
|
|
|
|
|
|
|
|
3
|
10
|
|
|
10
|
|
391093
|
use 5.016; |
|
10
|
|
|
|
|
111
|
|
4
|
10
|
|
|
10
|
|
48
|
use warnings; |
|
10
|
|
|
|
|
16
|
|
|
10
|
|
|
|
|
279
|
|
5
|
10
|
|
|
10
|
|
49
|
use Carp; |
|
10
|
|
|
|
|
16
|
|
|
10
|
|
|
|
|
813
|
|
6
|
10
|
|
|
10
|
|
59
|
use Scalar::Util 'looks_like_number'; |
|
10
|
|
|
|
|
16
|
|
|
10
|
|
|
|
|
861
|
|
7
|
10
|
|
|
10
|
|
68
|
use List::Util qw< min max uniq>; |
|
10
|
|
|
|
|
21
|
|
|
10
|
|
|
|
|
1180
|
|
8
|
10
|
|
|
10
|
|
4170
|
use version; |
|
10
|
|
|
|
|
18087
|
|
|
10
|
|
|
|
|
60
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $VERSION = '0.000005'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# Default naming scheme for refactoring... |
13
|
|
|
|
|
|
|
my $DEFAULT_SUB_NAME = '__REFACTORED_SUB__'; |
14
|
|
|
|
|
|
|
my $DEFAULT_LEXICAL_NAME = '__HOISTED_LEXICAL__'; |
15
|
|
|
|
|
|
|
my $DEFAULT_DATA_PARAM = '@__EXTRA_DATA__'; |
16
|
|
|
|
|
|
|
my $DEFAULT_AUTO_RETURN_VALUE = '@__RETURN_VALUE__'; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# These are the permitted options for refactor_to_sub()... |
19
|
|
|
|
|
|
|
my %VALID_REFACTOR_OPTION = ( name=>1, from=>1, to=>1, data=>1, return=>1 ); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# These are the permitted options for hoist_to_lexical()... |
22
|
|
|
|
|
|
|
my %VALID_HOIST_OPTION = ( name=>1, from=>1, to=>1, closure=>1, all=>1 ); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# Load the module... |
25
|
|
|
|
|
|
|
sub import { |
26
|
10
|
|
|
10
|
|
168
|
my $package = shift; |
27
|
10
|
|
50
|
|
|
77
|
my $opt_ref = shift // {}; |
28
|
|
|
|
|
|
|
|
29
|
10
|
50
|
|
|
|
51
|
croak("Options argument to 'use $package' must be a hash reference") |
30
|
|
|
|
|
|
|
if ref($opt_ref) ne 'HASH'; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# # Remember lexically scoped options... |
33
|
|
|
|
|
|
|
# for my $optname (keys %{$opt_ref}) { |
34
|
|
|
|
|
|
|
# croak "Unknown option ('$optname') passed to 'use $package'" |
35
|
|
|
|
|
|
|
# if !$VALID_REFACTOR_OPTION{$optname} && !$VALID_HOIST_OPTION{$optname}; |
36
|
|
|
|
|
|
|
# $^H{"Code::ART $optname"} = $opt_ref->{$optname}; |
37
|
|
|
|
|
|
|
# } |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# Export the API... |
40
|
10
|
|
|
10
|
|
1594
|
no strict 'refs'; |
|
10
|
|
|
|
|
19
|
|
|
10
|
|
|
|
|
6775
|
|
41
|
10
|
|
|
|
|
29
|
*{caller().'::refactor_to_sub'} = \&refactor_to_sub; |
|
10
|
|
|
|
|
93
|
|
42
|
10
|
|
|
|
|
27
|
*{caller().'::rename_variable'} = \&rename_variable; |
|
10
|
|
|
|
|
62
|
|
43
|
10
|
|
|
|
|
24
|
*{caller().'::classify_all_vars_in'} = \&classify_all_vars_in; |
|
10
|
|
|
|
|
118
|
|
44
|
10
|
|
|
|
|
26
|
*{caller().'::hoist_to_lexical'} = \&hoist_to_lexical; |
|
10
|
|
|
|
|
5431
|
|
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# This regex recognizes variables that don't need to be passed in |
49
|
|
|
|
|
|
|
# even if they're not locally declared... |
50
|
|
|
|
|
|
|
my $PERL_SPECIAL_VAR = qr{ |
51
|
|
|
|
|
|
|
\A |
52
|
|
|
|
|
|
|
[\$\@%] |
53
|
|
|
|
|
|
|
(?: |
54
|
|
|
|
|
|
|
[][\d\{!"#\$%&'()*+,./:;<=>?\@\^`|~_-] |
55
|
|
|
|
|
|
|
| |
56
|
|
|
|
|
|
|
\^ .* |
57
|
|
|
|
|
|
|
| |
58
|
|
|
|
|
|
|
\{\^ .* |
59
|
|
|
|
|
|
|
| |
60
|
|
|
|
|
|
|
ACCUMULATOR | ARG | ARGV | ARRAY_BASE | AUTOLOAD | BASETIME | CHILD_ERROR | |
61
|
|
|
|
|
|
|
COMPILING | DEBUGGING | EFFECTIVE_GROUP_ID | EFFECTIVE_USER_ID | EGID | ENV | |
62
|
|
|
|
|
|
|
ERRNO | EUID | EVAL_ERROR | EXCEPTIONS_BEING_CAUGHT | EXECUTABLE_NAME | |
63
|
|
|
|
|
|
|
EXTENDED_OS_ERROR | F | FORMAT_FORMFEED | FORMAT_LINES_LEFT | FORMAT_LINES_PER_PAGE | |
64
|
|
|
|
|
|
|
FORMAT_LINE_BREAK_CHARACTERS | FORMAT_NAME | FORMAT_PAGE_NUMBER | FORMAT_TOP_NAME | |
65
|
|
|
|
|
|
|
GID | INC | INPLACE_EDIT | INPUT_LINE_NUMBER | INPUT_RECORD_SEPARATOR | |
66
|
|
|
|
|
|
|
LAST_MATCH_END | LAST_MATCH_START | LAST_PAREN_MATCH | LAST_REGEXP_CODE_RESULT | |
67
|
|
|
|
|
|
|
LAST_SUBMATCH_RESULT | LIST_SEPARATOR | MATCH | NR | OFMT | OFS | OLD_PERL_VERSION | |
68
|
|
|
|
|
|
|
ORS | OSNAME | OS_ERROR | OUTPUT_AUTOFLUSH | OUTPUT_FIELD_SEPARATOR | |
69
|
|
|
|
|
|
|
OUTPUT_RECORD_SEPARATOR | PERLDB | PERL_VERSION | PID | POSTMATCH | PREMATCH | |
70
|
|
|
|
|
|
|
PROCESS_ID | PROGRAM_NAME | REAL_GROUP_ID | REAL_USER_ID | RS | SIG | SUBSCRIPT_SEPARATOR | |
71
|
|
|
|
|
|
|
SUBSEP | SYSTEM_FD_MAX | UID | WARNING | a | b |
72
|
|
|
|
|
|
|
) |
73
|
|
|
|
|
|
|
\Z |
74
|
|
|
|
|
|
|
}x; |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# What a simple variable looks like... |
77
|
|
|
|
|
|
|
my $SIMPLE_VAR = qr{ \A [\$\@%] [^\W\d] \w* \Z }xms; |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# What whitespace look like... |
80
|
|
|
|
|
|
|
my $OWS = qr{ (?: \s++ | \# [^\n]*+ (?> \n | \Z ))*+ }xms; |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# This is where the magic happens: parse the code and extract the undeclared variables... |
83
|
10
|
|
|
10
|
|
7255
|
use PPR::X; |
|
10
|
|
|
|
|
422266
|
|
|
10
|
|
|
|
|
423
|
|
84
|
10
|
|
|
10
|
|
122
|
use re 'eval'; |
|
10
|
|
|
|
|
22
|
|
|
10
|
|
|
|
|
16942
|
|
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# Refactor the code into a subroutine... |
87
|
|
|
|
|
|
|
sub refactor_to_sub { |
88
|
|
|
|
|
|
|
# Unpack args... |
89
|
8
|
|
|
8
|
0
|
6570
|
my ($opt_ref) = grep { ref($_) eq 'HASH' } @_, {}; |
|
22
|
|
|
|
|
88
|
|
90
|
8
|
|
|
|
|
22
|
my ($code, @extras) = grep { !ref($_) } @_; |
|
14
|
|
|
|
|
34
|
|
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# Check raw arguments... |
93
|
8
|
100
|
66
|
|
|
347
|
croak( "'code' argument of refactor_to_sub() must be a string" ) if !defined($code) || ref($code); |
94
|
6
|
|
|
|
|
111
|
croak( "Unexpected extra argument passed to refactor_to_sub(): '$_'" ) for @extras; |
95
|
|
|
|
|
|
|
croak( "'options' argument of refactor_to_sub() must be hash ref, not ", lc(ref($_)), " ref" ) |
96
|
5
|
100
|
|
|
|
12
|
for grep { ref($_) && ref($_) ne 'HASH' } @_; |
|
10
|
|
|
|
|
158
|
|
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# Apply defaults... |
99
|
4
|
|
100
|
|
|
26
|
my $from = $opt_ref->{from} // 0; |
100
|
4
|
|
50
|
|
|
20
|
my $to = $opt_ref->{to} // length($code // q{}) - 1; |
|
|
|
66
|
|
|
|
|
101
|
4
|
|
33
|
|
|
31
|
my $subname = $opt_ref->{name} // $DEFAULT_SUB_NAME; |
102
|
4
|
|
33
|
|
|
21
|
my $data = $opt_ref->{data} // $DEFAULT_DATA_PARAM; |
103
|
4
|
|
|
|
|
18
|
$data =~ s{\A\s*(\w)}{\@$1}xms; |
104
|
4
|
|
|
|
|
10
|
my $return_expr = $opt_ref->{return}; |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# Check processed arguments... |
107
|
|
|
|
|
|
|
croak( "Unknown option ('$_') passed to refactor_to_sub()" ) |
108
|
4
|
|
|
|
|
8
|
for grep { !$VALID_REFACTOR_OPTION{$_} } keys %{$opt_ref}; |
|
7
|
|
|
|
|
112
|
|
|
4
|
|
|
|
|
14
|
|
109
|
|
|
|
|
|
|
croak( "'from' option of refactor_to_sub() must be a number" ) |
110
|
3
|
50
|
|
|
|
19
|
if !looks_like_number($opt_ref->{from}); |
111
|
|
|
|
|
|
|
croak( "'to' option of refactor_to_sub() must be a number" ) |
112
|
3
|
50
|
|
|
|
12
|
if !looks_like_number($opt_ref->{to}); |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# Extract target code being factored out... |
115
|
3
|
|
|
|
|
9
|
my $target_code = substr($code, $from, $to-$from+1); |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# Extract any trailing semicolon or comma that may need to be preserved... |
118
|
3
|
|
|
|
|
328
|
$target_code =~ m{ (? $OWS ) |
119
|
|
|
|
|
|
|
(? |
120
|
|
|
|
|
|
|
(?> (? ; ) |
121
|
|
|
|
|
|
|
| (? , | => | ) |
122
|
|
|
|
|
|
|
) |
123
|
|
|
|
|
|
|
) |
124
|
|
|
|
|
|
|
$OWS \Z |
125
|
|
|
|
|
|
|
}xmso; |
126
|
3
|
|
|
|
|
63
|
my %trailing = %+; |
127
|
3
|
|
|
|
|
19
|
$trailing{punctuation} = ($trailing{ows} =~ s/\S/ /gr) . $trailing{punctuation}; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# Check if the end of the target code is the end of the file... |
130
|
3
|
50
|
|
|
|
98
|
my $final_semicolon = substr($code, $to) =~ m{ $OWS \S }xmso ? q{} : q{;}; |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# Ensure that the code is refactorable... |
133
|
3
|
|
|
|
|
13
|
local %Code::ART::retloc = (); |
134
|
3
|
|
|
|
|
6
|
local $Code::ART::insub; $Code::ART::insub = 0; |
|
3
|
|
|
|
|
5
|
|
135
|
|
|
|
|
|
|
my $statement_sequence = qr{ |
136
|
|
|
|
|
|
|
(?>(?&PerlEntireDocument)) |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
(?(DEFINE) |
139
|
|
|
|
|
|
|
(? |
140
|
10
|
|
|
|
|
137
|
(?{ $Code::ART::insub++ }) |
141
|
|
|
|
|
|
|
(?>(?&PerlStdSubroutineDeclaration)) |
142
|
0
|
|
|
|
|
0
|
(?{ $Code::ART::insub-- }) |
143
|
|
|
|
|
|
|
| |
144
|
10
|
|
|
|
|
140
|
(?{ $Code::ART::insub-- }) |
145
|
|
|
|
|
|
|
(?!) |
146
|
|
|
|
|
|
|
) |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
(? |
149
|
26
|
|
|
|
|
99
|
(?{ $Code::ART::insub++ }) |
150
|
|
|
|
|
|
|
(?>(?&PerlStdAnonymousSubroutine)) |
151
|
0
|
|
|
|
|
0
|
(?{ $Code::ART::insub-- }) |
152
|
|
|
|
|
|
|
| |
153
|
26
|
|
|
|
|
3915
|
(?{ $Code::ART::insub-- }) |
154
|
|
|
|
|
|
|
(?!) |
155
|
|
|
|
|
|
|
) |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
(? |
158
|
26
|
|
|
|
|
311
|
(?{ pos() }) |
159
|
|
|
|
|
|
|
(?&PerlStdReturnExpression) |
160
|
|
|
|
|
|
|
(?= (?&PerlOWS) ;? (?&PerlOWS) |
161
|
0
|
0
|
|
|
|
0
|
(?{ $Code::ART::retloc{pos()} = $^R if !$Code::ART::insub; }) ) |
162
|
|
|
|
|
|
|
) |
163
|
|
|
|
|
|
|
) |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
$PPR::X::GRAMMAR |
166
|
3
|
|
|
|
|
122145
|
}xmso; |
167
|
|
|
|
|
|
|
|
168
|
3
|
100
|
|
|
|
92582
|
my $test_code = $target_code =~ m{\A (?&PerlOWS) (?&PerlAssignmentOperator) $PPR::X::GRAMMAR }xmso |
169
|
|
|
|
|
|
|
? '()' . $target_code |
170
|
|
|
|
|
|
|
: $target_code; |
171
|
3
|
50
|
|
|
|
679
|
if ($test_code !~ $statement_sequence) { |
172
|
0
|
|
|
|
|
0
|
return { failed => 'not a valid series of statements', |
173
|
|
|
|
|
|
|
context => $PPR::X::ERROR, |
174
|
|
|
|
|
|
|
args => [] |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
3
|
|
|
|
|
120
|
my $final_return = exists $Code::ART::retloc{length($target_code)}; |
179
|
3
|
|
|
|
|
11
|
my $interim_return = keys %Code::ART::retloc > $final_return; |
180
|
3
|
50
|
33
|
|
|
15
|
if ($interim_return && !$final_return) { |
181
|
0
|
|
|
|
|
0
|
return { failed => 'the code has an internal return statement', |
182
|
|
|
|
|
|
|
context => $PPR::X::ERROR, |
183
|
|
|
|
|
|
|
args => [] |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# Find all variables and scopes in the code (if possible)... |
188
|
3
|
|
|
|
|
15
|
my $vardata = classify_all_vars_in($code); |
189
|
3
|
100
|
|
|
|
26
|
return { %{$vardata}, args => [] } if $vardata->{failed}; |
|
1
|
|
|
|
|
23
|
|
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
# Extract relevant variables... |
192
|
2
|
|
|
|
|
6
|
my (@in_vars, @out_vars, @lex_vars); |
193
|
2
|
|
|
|
|
4
|
for my $decl (sort {$a<=>$b} grep { $_ >= 0 } keys %{$vardata->{vars}}) { |
|
9
|
|
|
|
|
12
|
|
|
9
|
|
|
|
|
22
|
|
|
2
|
|
|
|
|
9
|
|
194
|
|
|
|
|
|
|
# No need to consider variables declared after the target... |
195
|
7
|
50
|
|
|
|
16
|
last if $decl > $to; |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# Was the variable declared before the target, and used inside it??? |
198
|
7
|
|
|
|
|
11
|
my $used = $vardata->{vars}{$decl}{used_at}; |
199
|
7
|
50
|
|
|
|
13
|
if ($decl < $from) { |
200
|
7
|
100
|
|
|
|
8
|
my @usages = grep { $from <= $_ && $_ <= $to } keys %{$used} |
|
4
|
100
|
|
|
|
19
|
|
|
7
|
|
|
|
|
20
|
|
201
|
|
|
|
|
|
|
or next; |
202
|
3
|
|
|
|
|
6
|
push @in_vars, { %{$vardata->{vars}{$decl}}, used_at => \@usages }; |
|
3
|
|
|
|
|
24
|
|
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# Was the variable declared within the target, and used after it??? |
206
|
|
|
|
|
|
|
else { |
207
|
0
|
|
|
|
|
0
|
my @usages = grep { $_ <= $to } keys %{$used}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
208
|
0
|
0
|
|
|
|
0
|
if (grep { $_ > $to } keys %{$used}) { |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
209
|
0
|
|
|
|
|
0
|
push @out_vars, { %{$vardata->{vars}{$decl}}, used_at => \@usages }; |
|
0
|
|
|
|
|
0
|
|
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
else { |
212
|
0
|
|
|
|
|
0
|
push @lex_vars, { %{$vardata->{vars}{$decl}}, used_at => \@usages }; |
|
0
|
|
|
|
|
0
|
|
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
# Determine minimal version of Perl 5 being used... |
218
|
2
|
|
|
|
|
6
|
my $use_version = $vardata->{use_version}; |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# Convert target code to an independent refactorable equivalent... |
221
|
2
|
|
|
|
|
13
|
my %convert_opts |
222
|
|
|
|
|
|
|
= (from=>$from, to=>$to, in_vars=>\@in_vars, out_vars=>\@out_vars, lex_vars =>\@lex_vars); |
223
|
2
|
|
|
|
|
10
|
my ($arg_code, $param_code, $refactored_code, $return_candidates) |
224
|
|
|
|
|
|
|
= _convert_target_code($target_code, \%convert_opts); |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# Extract any leading whitespace or assignment to be preserved... |
227
|
2
|
|
|
|
|
61663
|
$refactored_code =~ s{ \A (? (?>(?&PerlOWS)) ) |
228
|
|
|
|
|
|
|
(?> |
229
|
|
|
|
|
|
|
(? |
230
|
|
|
|
|
|
|
(?>(?&PerlAssignmentOperator)) (?>(?&PerlOWS)) |
231
|
|
|
|
|
|
|
) |
232
|
|
|
|
|
|
|
(? |
233
|
|
|
|
|
|
|
(?>(?&PerlConditionalExpression)) |
234
|
|
|
|
|
|
|
) |
235
|
|
|
|
|
|
|
)?+ |
236
|
|
|
|
|
|
|
(?= (? (?>(?&PerlOWS)) ;?+ (?>(?&PerlOWS)) \z | ) ) |
237
|
|
|
|
|
|
|
$PPR::X::GRAMMAR |
238
|
2
|
|
|
|
|
2189
|
}{ ' ' x length($&) }exmso; |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
my ($leading_ws, $leading_assignment, $leading_assignment_expr, $single_expr) |
241
|
2
|
|
|
|
|
396
|
= @+{qw< leading_ws leading_assignment leading_assignment_expr single_expr>}; |
242
|
2
|
|
50
|
|
|
17
|
$leading_ws //= q{}; |
243
|
2
|
|
100
|
|
|
12
|
$leading_assignment //= q{}; |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# Insert code to handle trailing arguments (if any)... |
246
|
2
|
100
|
66
|
|
|
20
|
if ($trailing{comma} || !$trailing{semicolon} ) { |
247
|
1
|
50
|
|
|
|
5
|
$param_code .= "," if $param_code =~ /\S/; |
248
|
1
|
|
|
|
|
4
|
$param_code .= " $data"; |
249
|
1
|
|
|
|
|
13
|
$refactored_code =~ s{\s* \Z}{ $data;\n}xms; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# Reinstate leading assignment (if any) and install return value (if any)... |
253
|
2
|
100
|
|
|
|
10
|
if ($leading_assignment) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
254
|
1
|
50
|
|
|
|
4
|
if ($final_return) { |
255
|
0
|
|
|
|
|
0
|
return { failed => "code has both a leading assignment and an explicit return", |
256
|
|
|
|
|
|
|
args => [], |
257
|
|
|
|
|
|
|
}; |
258
|
|
|
|
|
|
|
} |
259
|
1
|
50
|
|
|
|
3
|
if ($single_expr) { |
260
|
1
|
|
|
|
|
34
|
$refactored_code = $leading_ws . $leading_assignment_expr; |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
else { |
263
|
0
|
|
|
|
|
0
|
$refactored_code =~ s{\A \s*} |
264
|
0
|
|
|
|
|
0
|
{ my $DEFAULT_AUTO_RETURN_VALUE = wantarray ? ($leading_assignment_expr) : scalar($leading_assignment_expr)}xms; |
265
|
|
|
|
|
|
|
$refactored_code =~ s{\s* \Z} |
266
|
|
|
|
|
|
|
{\n ;\n return wantarray ? $DEFAULT_AUTO_RETURN_VALUE : shift $DEFAULT_AUTO_RETURN_VALUE;\n}xms; |
267
|
|
|
|
|
|
|
} |
268
|
0
|
|
|
|
|
0
|
} |
|
0
|
|
|
|
|
0
|
|
269
|
0
|
|
|
|
|
0
|
elsif (defined $return_expr) { |
270
|
|
|
|
|
|
|
my %refactored_name = map { $_->{decl_name} => $_->{new_name} } @in_vars, @out_vars; |
271
|
|
|
|
|
|
|
$return_expr |
272
|
|
|
|
|
|
|
=~ s{ (? \$\# (?&PerlOWS) \K (? \w++ ) |
273
|
|
|
|
|
|
|
| \@ (?&PerlOWS) \K (? \w++ ) (?! (?&PerlOWS) \{ ) |
274
|
|
|
|
|
|
|
| [\$%] (?&PerlOWS) \K (? \w++ ) (?= (?&PerlOWS) \[ ) |
275
|
|
|
|
|
|
|
) |
276
|
|
|
|
|
|
|
| |
277
|
|
|
|
|
|
|
(? |
278
|
|
|
|
|
|
|
\% (?&PerlOWS) \K (? \w++ ) (?! (?&PerlOWS) \[ ) |
279
|
|
|
|
|
|
|
| [\$\@] (?&PerlOWS) \K (? \w++ ) (?= (?&PerlOWS) \{ ) |
280
|
|
|
|
|
|
|
) |
281
|
|
|
|
|
|
|
| |
282
|
|
|
|
|
|
|
(? \$ (?&PerlOWS) \K (? \w++ ) (?! (?&PerlOWS) [\{\[] ) ) |
283
|
|
|
|
|
|
|
$PPR::X::GRAMMAR |
284
|
0
|
0
|
|
|
|
0
|
} |
|
|
0
|
|
|
|
|
|
285
|
0
|
0
|
|
|
|
0
|
{ my $new_name = $+{array} ? $refactored_name{"\@$+{varname}"} |
286
|
|
|
|
|
|
|
: $+{hash} ? $refactored_name{ "%$+{varname}"} |
287
|
0
|
|
|
|
|
0
|
: $refactored_name{"\$$+{varname}"}; |
288
|
|
|
|
|
|
|
defined($new_name) ? "{$new_name}" : $+{varname}; |
289
|
|
|
|
|
|
|
}gexmso; |
290
|
0
|
|
|
|
|
0
|
$refactored_code =~ s{\s* \Z}{\n ;\n return $return_expr\n}xms; |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
elsif ($final_return) { |
293
|
1
|
|
|
|
|
10
|
$leading_assignment = 'return '; |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
else { |
296
|
|
|
|
|
|
|
$refactored_code =~ s{\s* \Z}{\n ;\n # RETURN VALUE HERE?\n}xms; |
297
|
2
|
|
|
|
|
11
|
} |
|
5
|
|
|
|
|
14
|
|
|
5
|
|
|
|
|
20
|
|
298
|
2
|
|
|
|
|
49
|
|
299
|
2
|
50
|
|
|
|
49
|
# Format and wrap refactored code in a subroutine declaration... |
300
|
|
|
|
|
|
|
my $min_indent = min map { /^\s*/; length($&) } split(/\n/, $refactored_code); |
301
|
|
|
|
|
|
|
$refactored_code =~ s{ ^ [ ]{$min_indent} }{ }gxms; |
302
|
|
|
|
|
|
|
$refactored_code = "sub $subname" |
303
|
|
|
|
|
|
|
. ($use_version ge v5.22 |
304
|
|
|
|
|
|
|
? " ($param_code) {\n" |
305
|
|
|
|
|
|
|
: " {\n my ($param_code) = \@_;\n\n" |
306
|
|
|
|
|
|
|
) |
307
|
|
|
|
|
|
|
. "$refactored_code\n}\n"; |
308
|
|
|
|
|
|
|
|
309
|
2
|
100
|
66
|
|
|
24
|
my $call = $leading_ws . $leading_assignment |
310
|
|
|
|
|
|
|
. $subname |
311
|
2
|
|
|
|
|
166
|
. ($trailing{comma} || !$trailing{semicolon} ? " $arg_code" : "($arg_code)") |
312
|
|
|
|
|
|
|
. $trailing{punctuation}; |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
return { code => $refactored_code, |
315
|
|
|
|
|
|
|
call => $call . $final_semicolon, |
316
|
|
|
|
|
|
|
return => $return_candidates, |
317
|
|
|
|
|
|
|
}; |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
3
|
|
|
3
|
0
|
287
|
# Refactor the code into a subroutine... |
|
9
|
|
|
|
|
24
|
|
321
|
3
|
|
|
|
|
9
|
sub hoist_to_lexical { |
|
6
|
|
|
|
|
15
|
|
322
|
|
|
|
|
|
|
# Unpack args... |
323
|
|
|
|
|
|
|
my ($opt_ref) = grep { ref($_) eq 'HASH' } @_, {}; |
324
|
3
|
50
|
33
|
|
|
22
|
my ($code, @extras) = grep { !ref($_) } @_; |
325
|
3
|
|
|
|
|
10
|
|
326
|
|
|
|
|
|
|
# Check raw arguments... |
327
|
3
|
100
|
|
|
|
9
|
croak( "'code' argument of refactor_to_sub() must be a string" ) if !defined($code) || ref($code); |
|
6
|
|
|
|
|
25
|
|
328
|
|
|
|
|
|
|
croak( "Unexpected extra argument passed to refactor_to_sub(): '$_'" ) for @extras; |
329
|
|
|
|
|
|
|
croak( "'options' argument of refactor_to_sub() must be hash ref, not ", lc(ref($_)), " ref" ) |
330
|
3
|
|
33
|
|
|
23
|
for grep { ref($_) && ref($_) ne 'HASH' } @_; |
331
|
3
|
|
50
|
|
|
12
|
|
332
|
3
|
|
0
|
|
|
9
|
# Apply defaults... |
|
|
|
33
|
|
|
|
|
333
|
3
|
|
|
|
|
6
|
my $varname = $opt_ref->{name} // $DEFAULT_LEXICAL_NAME; |
334
|
3
|
|
|
|
|
6
|
my $from = $opt_ref->{from} // 0; |
335
|
|
|
|
|
|
|
my $to = $opt_ref->{to} // length($code // q{}) - 1; |
336
|
|
|
|
|
|
|
my $all = $opt_ref->{all}; |
337
|
|
|
|
|
|
|
my $closure = $opt_ref->{closure}; |
338
|
3
|
|
|
|
|
6
|
|
|
12
|
|
|
|
|
28
|
|
|
3
|
|
|
|
|
21
|
|
339
|
|
|
|
|
|
|
# Check processed arguments... |
340
|
3
|
50
|
|
|
|
18
|
croak( "Unknown option ('$_') passed to refactor_to_sub()" ) |
341
|
|
|
|
|
|
|
for grep { !$VALID_HOIST_OPTION{$_} } keys %{$opt_ref}; |
342
|
3
|
50
|
|
|
|
13
|
croak( "'from' option of hoist_to_lexical() must be a number" ) |
343
|
|
|
|
|
|
|
if !looks_like_number($opt_ref->{from}); |
344
|
|
|
|
|
|
|
croak( "'to' option of hoist_to_lexical() must be a number" ) |
345
|
3
|
|
|
|
|
9
|
if !looks_like_number($opt_ref->{to}); |
346
|
3
|
50
|
|
|
|
21
|
|
347
|
|
|
|
|
|
|
# Analyze the file to locate replaceable instances of the expression... |
348
|
|
|
|
|
|
|
my $expr_scope = find_expr_scope($code, $from, $to, $all); |
349
|
3
|
|
|
|
|
9
|
return $expr_scope if $expr_scope->{failed}; |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
# Extract target code... |
352
|
3
|
|
66
|
|
|
16
|
my $target = $expr_scope->{target}; |
|
|
|
100
|
|
|
|
|
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
# Handle mutators... |
355
|
3
|
|
|
|
|
6
|
$closure ||= $expr_scope->{mutators} > 0 && @{$expr_scope->{matches}} > 1; |
356
|
3
|
|
|
|
|
5
|
|
357
|
3
|
50
|
|
|
|
12
|
# Convert the name and the "call" name to the correct syntax... |
358
|
3
|
100
|
|
|
|
34
|
my $varsubst = $varname; |
|
|
50
|
|
|
|
|
|
359
|
1
|
|
|
|
|
3
|
my $vardecl; |
360
|
1
|
|
|
|
|
3
|
if ($varname !~ /^[\$\@%]/) { |
361
|
|
|
|
|
|
|
if (!$closure) { |
362
|
|
|
|
|
|
|
$varsubst = $varname = '$'.$varname; |
363
|
0
|
|
|
|
|
0
|
$vardecl = "my $varname = $target;\n"; |
364
|
0
|
|
|
|
|
0
|
} |
365
|
0
|
|
|
|
|
0
|
elsif ($expr_scope->{use_version} lt v5.26) { |
366
|
|
|
|
|
|
|
$varname = '$'.$varname; |
367
|
|
|
|
|
|
|
$varsubst = $varname . '->()'; |
368
|
2
|
|
|
|
|
7
|
$vardecl = "my $varname = sub { $target };\n"; |
369
|
2
|
|
|
|
|
8
|
} |
370
|
|
|
|
|
|
|
else { |
371
|
|
|
|
|
|
|
$varsubst = $varname.'()'; |
372
|
|
|
|
|
|
|
$vardecl = "my sub $varname { $target }\n"; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
3
|
|
|
|
|
10
|
# Return analysis... |
|
3
|
|
|
|
|
32
|
|
377
|
|
|
|
|
|
|
return { code => $vardecl, |
378
|
|
|
|
|
|
|
call => $varsubst, |
379
|
|
|
|
|
|
|
%{$expr_scope}, |
380
|
|
|
|
|
|
|
}; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
3
|
|
|
3
|
0
|
10
|
my $SPACE_MARKER = "\1\0\1\0\1\0"; |
384
|
|
|
|
|
|
|
my $SPACE_FINDER = quotemeta $SPACE_MARKER; |
385
|
3
|
|
|
|
|
8
|
sub find_expr_scope { |
386
|
3
|
|
|
|
|
94027
|
my ($source, $from, $to, $match_all) = @_; |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
my $target = substr($source, $from, $to-$from+1); |
389
|
10
|
|
|
10
|
|
122
|
$target =~ s{ \A (?>(?&PerlOWS)) | (?>(?&PerlOWS)) \Z $PPR::X::GRAMMAR }{}gxmso; |
|
10
|
|
|
|
|
24
|
|
|
10
|
|
|
|
|
43379
|
|
390
|
3
|
|
|
|
|
451
|
|
391
|
3
|
|
|
|
|
10
|
# Verify it's a valid target... |
392
|
|
|
|
|
|
|
use re 'eval'; |
393
|
|
|
|
|
|
|
our %ws_locs; |
394
|
|
|
|
|
|
|
our $mutators = 0; |
395
|
|
|
|
|
|
|
my $valid_target = qr{ |
396
|
73
|
|
|
|
|
849
|
\A (?>(?&PerlConditionalExpression)) \Z |
|
73
|
|
|
|
|
1086
|
|
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
(?(DEFINE) |
399
|
0
|
|
|
|
|
0
|
(? (?{pos()}) (?&PerlStdOWS) (?{ $ws_locs{$^R} = pos()-$^R; }) ) |
|
0
|
|
|
|
|
0
|
|
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
(? |
402
|
|
|
|
|
|
|
(?> \+\+ (?{$mutators++}) | -- (?{$mutators++ }) |
403
|
|
|
|
|
|
|
| [!\\+~] |
404
|
|
|
|
|
|
|
| - (?! (?&PPR_X_filetest_name) \b ) |
405
|
|
|
|
|
|
|
) |
406
|
1
|
|
|
|
|
7
|
) |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
(? |
409
|
|
|
|
|
|
|
(?> \+\+ | -- ) (?{ $mutators++ }) |
410
|
|
|
|
|
|
|
) |
411
|
3
|
|
|
|
|
109818
|
) |
412
|
|
|
|
|
|
|
|
413
|
3
|
50
|
|
|
|
478
|
$PPR::X::GRAMMAR |
414
|
0
|
|
|
|
|
0
|
}xms; |
415
|
0
|
|
|
|
|
0
|
|
416
|
|
|
|
|
|
|
if ($target !~ $valid_target) { |
417
|
|
|
|
|
|
|
return { failed => "it's not a simple expression", target => $target }; |
418
|
|
|
|
|
|
|
return; |
419
|
|
|
|
|
|
|
} |
420
|
3
|
|
|
|
|
10
|
|
421
|
3
|
|
|
|
|
15
|
# Convert the target text into a whitespace-tolerant literal search pattern |
|
28
|
|
|
|
|
39
|
|
|
20
|
|
|
|
|
52
|
|
422
|
17
|
|
|
|
|
35
|
# and whitespace-minimized rvalue for initializing hoist variable... |
423
|
|
|
|
|
|
|
my $rvalue = $target; |
424
|
17
|
|
|
|
|
27
|
for my $loc (sort {$b<=>$a} grep { $_ < length($target) } keys %ws_locs) { |
425
|
17
|
100
|
|
|
|
49
|
substr($target, $loc, $ws_locs{$loc}, $SPACE_MARKER); |
426
|
|
|
|
|
|
|
|
427
|
3
|
|
|
|
|
14
|
my $raw_ws = substr($rvalue, $loc, $ws_locs{$loc}); |
428
|
3
|
|
|
|
|
50
|
substr($rvalue, $loc, $ws_locs{$loc}, $raw_ws =~ /\s/ ? q{ } : q{}); |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
$target = quotemeta $target; |
431
|
3
|
|
|
|
|
8
|
$target =~ s{\Q$SPACE_FINDER\E}{\\s*+}gxms; |
432
|
3
|
|
|
|
|
65
|
|
|
13
|
|
|
|
|
57
|
|
433
|
12
|
|
|
|
|
127
|
# Locate all target instances... |
434
|
|
|
|
|
|
|
my @matches; |
435
|
|
|
|
|
|
|
while ($source =~ m{(?{pos()}) (? $target)}gcxms) { |
436
|
|
|
|
|
|
|
push @matches, {from => $^R, length => length($+{match}) }; |
437
|
3
|
|
|
|
|
18
|
} |
438
|
|
|
|
|
|
|
|
439
|
9
|
100
|
|
|
|
27
|
# Determine every variable in scope for the target expression... |
|
21
|
50
|
|
|
|
70
|
|
|
9
|
|
|
|
|
18
|
|
440
|
3
|
|
|
|
|
12
|
my $var_info = classify_all_vars_in($source); |
|
3
|
|
|
|
|
13
|
|
441
|
|
|
|
|
|
|
my @target_vars = grep { $_->{declared_at} >= 0 |
442
|
|
|
|
|
|
|
&& grep { $_ >= $from && $_ < $to } keys %{$_->{used_at} } } |
443
|
|
|
|
|
|
|
values %{$var_info->{vars}}; |
444
|
3
|
|
|
|
|
8
|
|
|
12
|
|
|
|
|
23
|
|
445
|
12
|
|
|
|
|
20
|
# Identify matches that use target variables... |
446
|
12
|
50
|
100
|
|
|
16
|
@matches = grep { |
|
48
|
|
|
|
|
137
|
|
447
|
|
|
|
|
|
|
my $match_from = $_->{from}; |
448
|
12
|
|
|
|
|
15
|
my $match_to = $match_from + $_->{length}; |
|
12
|
|
|
|
|
20
|
|
449
|
|
|
|
|
|
|
@target_vars == grep { grep { $match_all ? $match_from <= $_ && $_ <= $match_to |
450
|
|
|
|
|
|
|
: $match_from == $from } |
451
|
|
|
|
|
|
|
keys %{$_->{used_at}} |
452
|
|
|
|
|
|
|
} @target_vars; |
453
|
3
|
|
|
|
|
6
|
} @matches; |
|
3
|
|
|
|
|
12
|
|
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
# Identify earliest position where hoist could be placed... |
456
|
|
|
|
|
|
|
my $hoistloc = min map { $_->{start_of_scope} } @target_vars; |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
return { |
459
|
|
|
|
|
|
|
target => $rvalue, |
460
|
|
|
|
|
|
|
hoistloc => $hoistloc, |
461
|
3
|
|
|
|
|
284
|
matches => \@matches, |
462
|
|
|
|
|
|
|
mutators => $mutators, |
463
|
|
|
|
|
|
|
use_version => $var_info->{use_version}, |
464
|
|
|
|
|
|
|
}; |
465
|
2
|
|
|
2
|
|
6
|
} |
466
|
2
|
|
|
|
|
4
|
|
467
|
|
|
|
|
|
|
sub _convert_target_code { |
468
|
|
|
|
|
|
|
my ($target_code, $opts_ref) = @_; |
469
|
2
|
|
|
|
|
3
|
my $from = $opts_ref->{from}; |
|
2
|
|
|
|
|
7
|
|
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
# Label out-parameters... |
472
|
2
|
|
|
|
|
4
|
$_->{out} = 1 for @{$opts_ref->{out_vars}}; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
5
|
|
473
|
2
|
|
|
|
|
3
|
|
474
|
2
|
|
|
|
|
3
|
# Build name translation for each variable... |
475
|
2
|
|
|
|
|
6
|
my @param_vars = (@{$opts_ref->{in_vars}}, @{$opts_ref->{out_vars}}); |
476
|
|
|
|
|
|
|
our %rename_at; |
477
|
3
|
50
|
|
|
|
5
|
our %is_state_var; |
478
|
|
|
|
|
|
|
for my $var (@param_vars) { |
479
|
|
|
|
|
|
|
# Construct name of scalar parameter... |
480
|
|
|
|
|
|
|
my $out = $var->{out} ? 'o' : q{}; |
481
|
|
|
|
|
|
|
my $new_name |
482
|
|
|
|
|
|
|
= $var->{new_name} |
483
|
3
|
50
|
|
|
|
18
|
= '$'.$var->{raw_name} |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
484
|
|
|
|
|
|
|
. ( $var->{sigil} eq '@' ? "_${out}aref" |
485
|
|
|
|
|
|
|
: $var->{sigil} eq '%' ? "_${out}href" |
486
|
|
|
|
|
|
|
: $var->{raw_name} =~ /_o?(?:[ahs]ref|sval)$/ ? "_${out}sval" |
487
|
|
|
|
|
|
|
: "_${out}sref" |
488
|
3
|
|
50
|
|
|
7
|
); |
489
|
3
|
50
|
|
|
|
6
|
|
490
|
0
|
|
|
|
|
0
|
# Add "undeclarations" to renaming map and track internal state variables... |
491
|
0
|
|
|
|
|
0
|
my $local_decl = ($var->{declared_at} // -1) - $from; |
492
|
|
|
|
|
|
|
if ($local_decl >= 0) { |
493
|
|
|
|
|
|
|
$rename_at{$local_decl} = $new_name; |
494
|
|
|
|
|
|
|
$is_state_var{$local_decl} = $var->{declarator} eq 'state'; |
495
|
3
|
|
|
|
|
3
|
} |
|
3
|
|
|
|
|
6
|
|
496
|
3
|
|
|
|
|
8
|
|
497
|
|
|
|
|
|
|
# Add all usages to renaming map... |
498
|
|
|
|
|
|
|
for my $usage (@{$var->{used_at}}) { |
499
|
|
|
|
|
|
|
$rename_at{$usage - $from} = $new_name; |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
} |
502
|
3
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
5
|
|
503
|
2
|
|
|
|
|
4
|
# Build argument list and parameter list for call... |
|
0
|
|
|
|
|
0
|
|
|
2
|
|
|
|
|
6
|
|
504
|
|
|
|
|
|
|
my $args_code = join(', ', |
505
|
|
|
|
|
|
|
map( { "\\$_->{decl_name}" } @{$opts_ref->{in_vars}} ), |
506
|
2
|
|
|
|
|
5
|
map( { "\\$_->{declarator} $_->{decl_name}" } @{$opts_ref->{out_vars}} ) |
|
3
|
|
|
|
|
7
|
|
507
|
|
|
|
|
|
|
); |
508
|
|
|
|
|
|
|
|
509
|
2
|
|
|
|
|
62790
|
my $param_code = join(', ', map { "$_->{new_name}" } @param_vars); |
510
|
90
|
|
|
|
|
242
|
|
511
|
3
|
|
|
|
|
54
|
# Rename parameters within refactored code... |
512
|
|
|
|
|
|
|
$target_code =~ s{ (?: (?> my | our | state ) (?&PerlOWS) )?+ |
513
|
|
|
|
|
|
|
(?(?{$rename_at{pos()}})|(?!)) |
514
|
|
|
|
|
|
|
(?{pos()}) |
515
|
|
|
|
|
|
|
(? (?> \$\#?+ | [\@%] ) (?&PerlOWS) ) |
516
|
|
|
|
|
|
|
(? \{ (?&PerlOWS) | ) |
517
|
|
|
|
|
|
|
\w++ |
518
|
3
|
50
|
|
|
|
48
|
$PPR::X::GRAMMAR |
|
|
100
|
|
|
|
|
|
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
{ ( $is_state_var{$^R} ? "$&=" : q{} ) |
521
|
|
|
|
|
|
|
. $+{sigil} |
522
|
2
|
|
|
|
|
72090
|
. (length($+{braced}) ? "\{$rename_at{$^R}" : "{$rename_at{$^R}}") |
523
|
|
|
|
|
|
|
}egxmso; |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
# Rewrite list declarations to allow hoisting (skipping quoted ones)... |
526
|
|
|
|
|
|
|
$target_code =~ s{ (\A|\W) (?&PerlQuotelike) |
527
|
|
|
|
|
|
|
| (? |
528
|
|
|
|
|
|
|
(? (?> my | our | state ) ) (?&PerlOWS) |
529
|
|
|
|
|
|
|
\( (?&PerlOWS) |
530
|
|
|
|
|
|
|
(? (?&PerlVariable)?+ (?&PerlOWS) |
531
|
|
|
|
|
|
|
(?: , (?&PerlOWS) (?&PerlVariable) (?&PerlOWS) )*+ |
532
|
|
|
|
|
|
|
,?+ (?&PerlOWS) |
533
|
|
|
|
|
|
|
) |
534
|
2
|
50
|
|
|
|
28
|
\) |
535
|
0
|
|
|
|
|
0
|
) |
|
0
|
|
|
|
|
0
|
|
536
|
|
|
|
|
|
|
$PPR::X::GRAMMAR |
537
|
|
|
|
|
|
|
} |
538
|
2
|
|
|
|
|
334
|
{ |
539
|
|
|
|
|
|
|
if ($+{list_decl}) { |
540
|
|
|
|
|
|
|
'('.join(', ', map { "$+{declarator} $_" } split /,\s*/, $+{var_list}).')' |
541
|
|
|
|
|
|
|
} |
542
|
|
|
|
|
|
|
else { |
543
|
|
|
|
|
|
|
$&; |
544
|
0
|
|
|
|
|
0
|
} |
545
|
0
|
|
|
|
|
0
|
}egxmso; |
|
2
|
|
|
|
|
15
|
|
546
|
2
|
|
|
|
|
396
|
|
|
3
|
|
|
|
|
17
|
|
547
|
|
|
|
|
|
|
# Build old->name mapping... |
548
|
|
|
|
|
|
|
my $varname_mapping = { |
549
|
2
|
|
|
|
|
220
|
map( { $_->{decl_name} => $_->{decl_name} } |
550
|
|
|
|
|
|
|
grep { $_->{end_of_scope} >= $opts_ref->{to} } @{$opts_ref->{lex_vars}} ), |
551
|
|
|
|
|
|
|
map( { $_->{decl_name} => $_->{sigil}."{$_->{new_name}}" } @param_vars ), |
552
|
|
|
|
|
|
|
}; |
553
|
|
|
|
|
|
|
|
554
|
51
|
|
|
51
|
0
|
5833458
|
return ($args_code, $param_code, $target_code, $varname_mapping); |
555
|
|
|
|
|
|
|
} |
556
|
51
|
|
|
|
|
245
|
|
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
sub rename_variable { |
559
|
51
|
|
|
|
|
229
|
my ($source, $varpos, $new_name) = @_; |
|
51
|
|
|
|
|
230
|
|
560
|
|
|
|
|
|
|
|
561
|
51
|
50
|
|
|
|
157
|
my $extraction = _classify_var_at($source, $varpos); |
562
|
|
|
|
|
|
|
|
563
|
51
|
|
|
|
|
112
|
my ($varname, $declared_at, $used_at, $failed) |
|
522
|
|
|
|
|
638
|
|
|
51
|
|
|
|
|
303
|
|
564
|
269
|
50
|
|
|
|
8508554
|
= @{ $extraction }{'raw_name', 'declared_at', 'used_at', 'failed'}; |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
return { failed => $failed } if $failed; |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
for my $index (sort { $b <=> $a} keys %{$used_at}) { |
569
|
|
|
|
|
|
|
substr($source,$index) |
570
|
|
|
|
|
|
|
=~ s{\A (?: \$\#? | [\@%] ) (?&PerlOWS) |
571
|
|
|
|
|
|
|
\{? (?&PerlOWS) |
572
|
51
|
100
|
|
|
|
481
|
\K $varname $PPR::X::GRAMMAR |
573
|
44
|
50
|
|
|
|
1381141
|
}{$new_name}xms |
574
|
|
|
|
|
|
|
or warn "Internal usage rename error at position $index: '...", |
575
|
|
|
|
|
|
|
substr($source, $index, 20), "...'\n"; |
576
|
|
|
|
|
|
|
} |
577
|
|
|
|
|
|
|
if ($declared_at >= 0) { |
578
|
|
|
|
|
|
|
substr($source,$declared_at) |
579
|
|
|
|
|
|
|
=~ s{\A (?: \$\#? | [\@%] ) (?&PerlOWS) |
580
|
|
|
|
|
|
|
\{? (?&PerlOWS) |
581
|
|
|
|
|
|
|
\K $varname $PPR::X::GRAMMAR |
582
|
51
|
|
|
|
|
9751
|
}{$new_name}xms |
583
|
|
|
|
|
|
|
or warn "Internal declaration rename error at position $declared_at: '...", |
584
|
|
|
|
|
|
|
substr($source, $declared_at, 20), "...'\n"; |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
return { source => $source }; |
588
|
|
|
|
|
|
|
} |
589
|
0
|
|
|
0
|
|
0
|
|
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
|
592
|
0
|
|
|
|
|
0
|
# Convert fancy vars ($# { name }) to simple ones (@name)... |
593
|
|
|
|
|
|
|
sub _normalize_var { |
594
|
|
|
|
|
|
|
my ($var, $accessor) = @_; |
595
|
0
|
0
|
0
|
|
|
0
|
|
596
|
|
|
|
|
|
|
# Remove decorations... |
597
|
|
|
|
|
|
|
$var =~ tr/{} \t\n\f\r//d; |
598
|
0
|
0
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
|
|
599
|
|
|
|
|
|
|
# Convert maxindex ($#a) to array (@a) |
600
|
|
|
|
|
|
|
return '@'.substr($var,2) if length($var) > 2 && substr($var,0,2) eq '$#'; |
601
|
|
|
|
|
|
|
|
602
|
0
|
0
|
|
|
|
0
|
# Convert derefs (@$s or %$s) to scalar ($s) |
603
|
|
|
|
|
|
|
return substr($var,1) if length($var) > 2 |
604
|
|
|
|
|
|
|
&& (substr($var,0,2) eq '@$' || substr($var,0,2) eq '%$'); |
605
|
0
|
0
|
|
|
|
0
|
|
606
|
0
|
0
|
|
|
|
0
|
# Return entire variables as-are... |
607
|
|
|
|
|
|
|
return $var if !$accessor; |
608
|
|
|
|
|
|
|
|
609
|
0
|
|
|
|
|
0
|
# Convert array and hash look-ups to arrays and hashes... |
610
|
|
|
|
|
|
|
return '@'.substr($var,1) if $accessor eq '['; |
611
|
|
|
|
|
|
|
return '%'.substr($var,1) if $accessor eq '{'; |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
# "This can never happen" ;-) |
614
|
0
|
|
|
0
|
|
0
|
die "Internal error: unexpected accessor after $var: '$accessor'"; |
615
|
|
|
|
|
|
|
} |
616
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
617
|
|
|
|
|
|
|
# Extract variables from a for loop declaration... |
618
|
|
|
|
|
|
|
sub _extract_vars { |
619
|
|
|
|
|
|
|
my ($decl) = @_; |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
return map { _normalize_var($_) } |
622
|
0
|
|
|
0
|
|
0
|
$decl =~ m{ [\$\@%] \w+ }xmsg; |
623
|
0
|
|
|
|
|
0
|
} |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
# Remove 'use experimental' declarations if not requested... |
626
|
|
|
|
|
|
|
sub _de_experiment { |
627
|
|
|
|
|
|
|
my ($code) = @_; |
628
|
0
|
|
|
|
|
0
|
$code =~ s{ ^ $OWS |
629
|
|
|
|
|
|
|
use \s+ experimental\b $OWS |
630
|
|
|
|
|
|
|
(?>(?&PerlExpression)) $OWS |
631
|
|
|
|
|
|
|
; $OWS \n? |
632
|
|
|
|
|
|
|
}{}gxmso; |
633
|
|
|
|
|
|
|
return $code; |
634
|
|
|
|
|
|
|
} |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
# How to recognize a variable... |
637
|
|
|
|
|
|
|
my $VAR_PAT = qr{ |
638
|
|
|
|
|
|
|
\A |
639
|
|
|
|
|
|
|
(? |
640
|
|
|
|
|
|
|
(? [\@\$%] ) (? \$ ) (?! [\$\{\w] ) |
641
|
|
|
|
|
|
|
| |
642
|
|
|
|
|
|
|
(? (?> \$ (?: [#] (?= (?> [\$^\w\{:+] | - (?! > ) ) ))?+ | [\@%] ) ) |
643
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
644
|
|
|
|
|
|
|
(?> (? (?&_varname) ) |
645
|
|
|
|
|
|
|
| \{ (?>(?&PerlOWS)) (? (?&_varname) ) (?>(?&PerlOWS)) \} |
646
|
|
|
|
|
|
|
) |
647
|
|
|
|
|
|
|
| |
648
|
|
|
|
|
|
|
(? [\@\$%] ) (? \# ) |
649
|
|
|
|
|
|
|
) |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
(?(DEFINE) |
652
|
|
|
|
|
|
|
(?<_varname> \d++ |
653
|
|
|
|
|
|
|
| \^ [][A-Z^_?\\] |
654
|
|
|
|
|
|
|
| (?>(?&PerlOldQualifiedIdentifier)) (?: :: )?+ |
655
|
|
|
|
|
|
|
| [][!"#\$%&'()*+,.\\/:;<=>?\@\^`|~-] |
656
|
|
|
|
|
|
|
) |
657
|
|
|
|
|
|
|
) |
658
|
51
|
|
|
51
|
|
157
|
|
659
|
|
|
|
|
|
|
$PPR::X::GRAMMAR |
660
|
|
|
|
|
|
|
}xms; |
661
|
51
|
|
|
|
|
106
|
|
662
|
51
|
|
|
|
|
121
|
sub _classify_var_at { |
663
|
51
|
|
|
|
|
98
|
my ($source, $varpos) = @_; |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
# Locate the variable... |
666
|
51
|
|
|
|
|
231
|
my $orig_varpos = $varpos; |
667
|
|
|
|
|
|
|
my $orig_sigil = q{}; |
668
|
51
|
50
|
|
|
|
2076
|
my %var; |
669
|
51
|
|
|
|
|
2903
|
|
670
|
51
|
|
|
|
|
237
|
POSITION: |
671
|
|
|
|
|
|
|
while ($varpos >= 0) { |
672
|
|
|
|
|
|
|
# Walk backwards, looking for the variable... |
673
|
|
|
|
|
|
|
if (substr($source, $varpos) =~ $VAR_PAT) { |
674
|
51
|
50
|
33
|
|
|
520
|
%var = %+; |
|
|
|
33
|
|
|
|
|
675
|
|
|
|
|
|
|
$orig_sigil = $var{sigil}; |
676
|
|
|
|
|
|
|
|
677
|
51
|
50
|
|
|
|
222
|
# Handle the very special case of $; (need to be sure it's not part of $$;) |
678
|
0
|
|
|
|
|
0
|
next POSITION |
679
|
|
|
|
|
|
|
if $varpos > 0 && $var{name} eq ';' && substr($source, $varpos-1, 1) =~ /[\$\@%]/; |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
# Return a special value if we fail to match a variable at the specified position |
682
|
51
|
|
|
|
|
135
|
if ($varpos + length($var{full}) <= $orig_varpos) { |
683
|
|
|
|
|
|
|
return { failed => "No variable at specified location", at => $orig_varpos } |
684
|
|
|
|
|
|
|
} |
685
|
0
|
|
|
|
|
0
|
|
686
|
|
|
|
|
|
|
# Otherwise, we found it... |
687
|
|
|
|
|
|
|
last POSITION; |
688
|
51
|
50
|
|
|
|
188
|
} |
689
|
|
|
|
|
|
|
} |
690
|
|
|
|
|
|
|
continue { $varpos-- } |
691
|
|
|
|
|
|
|
|
692
|
51
|
|
|
|
|
181
|
# Did we run off the start of the input? |
693
|
|
|
|
|
|
|
return { failed => "No variable at specified location", at => $orig_varpos } |
694
|
|
|
|
|
|
|
if $varpos < 0; |
695
|
51
|
50
|
|
|
|
198
|
|
696
|
|
|
|
|
|
|
# Locate and classify every variable in the source code... |
697
|
|
|
|
|
|
|
my $analysis = classify_all_vars_in($source); |
698
|
51
|
|
|
|
|
109
|
|
699
|
51
|
|
|
|
|
88
|
# Return a failure report if unable to process source code... |
|
51
|
|
|
|
|
242
|
|
700
|
|
|
|
|
|
|
return $analysis if $analysis->{failed}; |
701
|
478
|
100
|
100
|
|
|
5111
|
|
702
|
|
|
|
|
|
|
# Attempt to locate and report information about the requested variable... |
703
|
|
|
|
|
|
|
my $allvars = $analysis->{vars}; |
704
|
0
|
|
|
|
|
0
|
for my $varid (keys %{$analysis->{vars}}) { |
705
|
|
|
|
|
|
|
return $allvars->{$varid} |
706
|
|
|
|
|
|
|
if $varid == $varpos || $allvars->{$varid}{used_at}{$varpos}; |
707
|
|
|
|
|
|
|
} |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
return { failed => 'Apparent variable is not actually a variable' }; |
710
|
|
|
|
|
|
|
} |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
# Descriptions of built-in and other "standard" variables... |
713
|
|
|
|
|
|
|
my %STD_VAR_DESC = ( |
714
|
|
|
|
|
|
|
"\$!" => { |
715
|
|
|
|
|
|
|
aliases => { "\$ERRNO" => 1, "\$OS_ERROR" => 1 }, |
716
|
|
|
|
|
|
|
desc => "Status from most recent system call (including I/O)", |
717
|
|
|
|
|
|
|
}, |
718
|
|
|
|
|
|
|
"\$\"" => { |
719
|
|
|
|
|
|
|
aliases => { "\$LIST_SEPARATOR" => 1 }, |
720
|
|
|
|
|
|
|
desc => "List separator for array interpolation", |
721
|
|
|
|
|
|
|
}, |
722
|
|
|
|
|
|
|
"\$#" => { |
723
|
|
|
|
|
|
|
aliases => { "\$OFMT" => 1 }, |
724
|
|
|
|
|
|
|
desc => "Output number format [deprecated: use printf() instead]", |
725
|
|
|
|
|
|
|
}, |
726
|
|
|
|
|
|
|
"\$\$" => { |
727
|
|
|
|
|
|
|
aliases => { "\$PID" => 1, "\$PROCESS_ID" => 1 }, |
728
|
|
|
|
|
|
|
desc => "Process ID", |
729
|
|
|
|
|
|
|
}, |
730
|
|
|
|
|
|
|
"\$%" => { |
731
|
|
|
|
|
|
|
aliases => { "\$FORMAT_PAGE_NUMBER" => 1 }, |
732
|
|
|
|
|
|
|
desc => "Page number of the current output page", |
733
|
|
|
|
|
|
|
}, |
734
|
|
|
|
|
|
|
"\$&" => { |
735
|
|
|
|
|
|
|
aliases => { "\$MATCH" => 1 }, |
736
|
|
|
|
|
|
|
desc => "Most recent regex match string", |
737
|
|
|
|
|
|
|
}, |
738
|
|
|
|
|
|
|
"\$'" => { |
739
|
|
|
|
|
|
|
aliases => { "\$POSTMATCH" => 1 }, |
740
|
|
|
|
|
|
|
desc => "String following most recent regex match", |
741
|
|
|
|
|
|
|
}, |
742
|
|
|
|
|
|
|
"\$(" => { |
743
|
|
|
|
|
|
|
aliases => { "\$GID" => 1, "\$REAL_GROUP_ID" => 1 }, |
744
|
|
|
|
|
|
|
desc => "Real group ID of the current process", |
745
|
|
|
|
|
|
|
}, |
746
|
|
|
|
|
|
|
"\$)" => { |
747
|
|
|
|
|
|
|
aliases => { "\$EFFECTIVE_GROUP_ID" => 1, "\$EGID" => 1 }, |
748
|
|
|
|
|
|
|
desc => "Effective group ID of the current process", |
749
|
|
|
|
|
|
|
}, |
750
|
|
|
|
|
|
|
"\$*" => { |
751
|
|
|
|
|
|
|
aliases => {}, |
752
|
|
|
|
|
|
|
desc => "Regex multiline matching flag [removed: use /m instead]", |
753
|
|
|
|
|
|
|
}, |
754
|
|
|
|
|
|
|
"\$+" => { |
755
|
|
|
|
|
|
|
aliases => { "\$LAST_PAREN_MATCH" => 1 }, |
756
|
|
|
|
|
|
|
desc => "Final capture group of most recent regex match", |
757
|
|
|
|
|
|
|
}, |
758
|
|
|
|
|
|
|
"\$," => { |
759
|
|
|
|
|
|
|
aliases => { "\$OFS" => 1, "\$OUTPUT_FIELD_SEPARATOR" => 1 }, |
760
|
|
|
|
|
|
|
desc => "Output field separator for print() and say()", |
761
|
|
|
|
|
|
|
}, |
762
|
|
|
|
|
|
|
"\$-" => { |
763
|
|
|
|
|
|
|
aliases => { "\$FORMAT_LINES_LEFT" => 1 }, |
764
|
|
|
|
|
|
|
desc => "Number of lines remaining in current output page", |
765
|
|
|
|
|
|
|
}, |
766
|
|
|
|
|
|
|
"\$." => { |
767
|
|
|
|
|
|
|
aliases => { "\$INPUT_LINE_NUMBER" => 1, "\$NR" => 1 }, |
768
|
|
|
|
|
|
|
desc => "Line number of last input line", |
769
|
|
|
|
|
|
|
}, |
770
|
|
|
|
|
|
|
"\$/" => { |
771
|
|
|
|
|
|
|
aliases => { "\$INPUT_RECORD_SEPARATOR" => 1, "\$RS" => 1 }, |
772
|
|
|
|
|
|
|
desc => "Input record separator (end-of-line marker on inputs)", |
773
|
|
|
|
|
|
|
}, |
774
|
|
|
|
|
|
|
"\$0" => { aliases => { "\$PROGRAM_NAME" => 1 }, desc => "Program name" }, |
775
|
|
|
|
|
|
|
"\$1" => { |
776
|
|
|
|
|
|
|
aliases => {}, |
777
|
|
|
|
|
|
|
desc => "First capture group from most recent regex match", |
778
|
|
|
|
|
|
|
}, |
779
|
|
|
|
|
|
|
"\$2" => { |
780
|
|
|
|
|
|
|
aliases => {}, |
781
|
|
|
|
|
|
|
desc => "Second capture group from most recent regex match", |
782
|
|
|
|
|
|
|
}, |
783
|
|
|
|
|
|
|
"\$3" => { |
784
|
|
|
|
|
|
|
aliases => {}, |
785
|
|
|
|
|
|
|
desc => "Third capture group from most recent regex match", |
786
|
|
|
|
|
|
|
}, |
787
|
|
|
|
|
|
|
"\$4" => { |
788
|
|
|
|
|
|
|
aliases => {}, |
789
|
|
|
|
|
|
|
desc => "Fourth capture group from most recent regex match", |
790
|
|
|
|
|
|
|
}, |
791
|
|
|
|
|
|
|
"\$5" => { |
792
|
|
|
|
|
|
|
aliases => {}, |
793
|
|
|
|
|
|
|
desc => "Fifth capture group from most recent regex match", |
794
|
|
|
|
|
|
|
}, |
795
|
|
|
|
|
|
|
"\$6" => { |
796
|
|
|
|
|
|
|
aliases => {}, |
797
|
|
|
|
|
|
|
desc => "Sixth capture group from most recent regex match", |
798
|
|
|
|
|
|
|
}, |
799
|
|
|
|
|
|
|
"\$7" => { |
800
|
|
|
|
|
|
|
aliases => {}, |
801
|
|
|
|
|
|
|
desc => "Seventh capture group from most recent regex match", |
802
|
|
|
|
|
|
|
}, |
803
|
|
|
|
|
|
|
"\$8" => { |
804
|
|
|
|
|
|
|
aliases => {}, |
805
|
|
|
|
|
|
|
desc => "Eighth capture group from most recent regex match", |
806
|
|
|
|
|
|
|
}, |
807
|
|
|
|
|
|
|
"\$9" => { |
808
|
|
|
|
|
|
|
aliases => {}, |
809
|
|
|
|
|
|
|
desc => "Ninth capture group from most recent regex match", |
810
|
|
|
|
|
|
|
}, |
811
|
|
|
|
|
|
|
"\$:" => { |
812
|
|
|
|
|
|
|
aliases => { "\$FORMAT_LINE_BREAK_CHARACTERS" => 1 }, |
813
|
|
|
|
|
|
|
desc => "Break characters for format() lines", |
814
|
|
|
|
|
|
|
}, |
815
|
|
|
|
|
|
|
"\$;" => { |
816
|
|
|
|
|
|
|
aliases => { "\$SUBSCRIPT_SEPARATOR" => 1, "\$SUBSEP" => 1 }, |
817
|
|
|
|
|
|
|
desc => "Hash subscript separator for key concatenation", |
818
|
|
|
|
|
|
|
}, |
819
|
|
|
|
|
|
|
"\$<" => { |
820
|
|
|
|
|
|
|
aliases => { "\$REAL_USER_ID" => 1, "\$UID" => 1 }, |
821
|
|
|
|
|
|
|
desc => "Real uid of the current process", |
822
|
|
|
|
|
|
|
}, |
823
|
|
|
|
|
|
|
"\$=" => { |
824
|
|
|
|
|
|
|
aliases => { "\$FORMAT_LINES_PER_PAGE" => 1 }, |
825
|
|
|
|
|
|
|
desc => "Page length of selected output channel", |
826
|
|
|
|
|
|
|
}, |
827
|
|
|
|
|
|
|
"\$>" => { |
828
|
|
|
|
|
|
|
aliases => { "\$EFFECTIVE_USER_ID" => 1, "\$EUID" => 1 }, |
829
|
|
|
|
|
|
|
desc => "Effective uid of the current process", |
830
|
|
|
|
|
|
|
}, |
831
|
|
|
|
|
|
|
"\$?" => { |
832
|
|
|
|
|
|
|
aliases => { "\$CHILD_ERROR" => 1 }, |
833
|
|
|
|
|
|
|
desc => "Status from most recent system call (including I/O)", |
834
|
|
|
|
|
|
|
}, |
835
|
|
|
|
|
|
|
"\$\@" => { |
836
|
|
|
|
|
|
|
aliases => { "\$EVAL_ERROR" => 1 }, |
837
|
|
|
|
|
|
|
desc => "Current propagating exception", |
838
|
|
|
|
|
|
|
}, |
839
|
|
|
|
|
|
|
"\$[" => { |
840
|
|
|
|
|
|
|
aliases => { "\$ARRAY_BASE" => 1 }, |
841
|
|
|
|
|
|
|
desc => "Array index origin [deprecated]", |
842
|
|
|
|
|
|
|
}, |
843
|
|
|
|
|
|
|
"\$\\" => { |
844
|
|
|
|
|
|
|
aliases => { "\$ORS" => 1, "\$OUTPUT_RECORD_SEPARATOR" => 1 }, |
845
|
|
|
|
|
|
|
desc => "Output record separator (appended to every print())", |
846
|
|
|
|
|
|
|
}, |
847
|
|
|
|
|
|
|
"\$]" => { |
848
|
|
|
|
|
|
|
aliases => {}, |
849
|
|
|
|
|
|
|
desc => "Perl interpreter version [deprecated: use \$^V]", |
850
|
|
|
|
|
|
|
}, |
851
|
|
|
|
|
|
|
"\$^" => { |
852
|
|
|
|
|
|
|
aliases => { "\$FORMAT_TOP_NAME" => 1 }, |
853
|
|
|
|
|
|
|
desc => "Name of top-of-page format for selected output channel", |
854
|
|
|
|
|
|
|
}, |
855
|
|
|
|
|
|
|
"\$^A" => { |
856
|
|
|
|
|
|
|
aliases => { "\$ACCUMULATOR" => 1 }, |
857
|
|
|
|
|
|
|
desc => "Accumulator for format() lines", |
858
|
|
|
|
|
|
|
}, |
859
|
|
|
|
|
|
|
"\$^C" => { |
860
|
|
|
|
|
|
|
aliases => { "\$COMPILING" => 1 }, |
861
|
|
|
|
|
|
|
desc => "Is the program still compiling?", |
862
|
|
|
|
|
|
|
}, |
863
|
|
|
|
|
|
|
"\$^D" => |
864
|
|
|
|
|
|
|
{ aliases => { "\$DEBUGGING" => 1 }, desc => "Debugging flags" }, |
865
|
|
|
|
|
|
|
"\$^E" => { |
866
|
|
|
|
|
|
|
aliases => { "\$EXTENDED_OS_ERROR" => 1 }, |
867
|
|
|
|
|
|
|
desc => "O/S specific error information", |
868
|
|
|
|
|
|
|
}, |
869
|
|
|
|
|
|
|
"\$^F" => { |
870
|
|
|
|
|
|
|
aliases => { "\$SYSTEM_FD_MAX" => 1 }, |
871
|
|
|
|
|
|
|
desc => "Maximum system file descriptor", |
872
|
|
|
|
|
|
|
}, |
873
|
|
|
|
|
|
|
"\$^H" => |
874
|
|
|
|
|
|
|
{ aliases => {}, desc => "Internal compile-time lexical hints" }, |
875
|
|
|
|
|
|
|
"\$^I" => { |
876
|
|
|
|
|
|
|
aliases => { "\$INPLACE_EDIT" => 1 }, |
877
|
|
|
|
|
|
|
desc => "In-place editing value", |
878
|
|
|
|
|
|
|
}, |
879
|
|
|
|
|
|
|
"\$^L" => { |
880
|
|
|
|
|
|
|
aliases => { "\$FORMAT_FORMFEED" => 1 }, |
881
|
|
|
|
|
|
|
desc => "Form-feed sequence for format() pages", |
882
|
|
|
|
|
|
|
}, |
883
|
|
|
|
|
|
|
"\$^M" => { aliases => {}, desc => "Emergency memory pool" }, |
884
|
|
|
|
|
|
|
"\$^N" => { |
885
|
|
|
|
|
|
|
aliases => { "\$LAST_SUBMATCH_RESULT" => 1 }, |
886
|
|
|
|
|
|
|
desc => "Most recent capture group (within regex)", |
887
|
|
|
|
|
|
|
}, |
888
|
|
|
|
|
|
|
"\$^O" => |
889
|
|
|
|
|
|
|
{ aliases => { "\$OSNAME" => 1 }, desc => "Operating system name" }, |
890
|
|
|
|
|
|
|
"\$^P" => |
891
|
|
|
|
|
|
|
{ aliases => { "\$PERLDB" => 1 }, desc => "Internal debugging flags" }, |
892
|
|
|
|
|
|
|
"\$^R" => { |
893
|
|
|
|
|
|
|
aliases => { "\$LAST_REGEXP_CODE_RESULT" => 1 }, |
894
|
|
|
|
|
|
|
desc => "Result of last successful code block (within regex)", |
895
|
|
|
|
|
|
|
}, |
896
|
|
|
|
|
|
|
"\$^S" => { |
897
|
|
|
|
|
|
|
aliases => { "\$EXCEPTIONS_BEING_CAUGHT" => 1 }, |
898
|
|
|
|
|
|
|
desc => "Current eval() state", |
899
|
|
|
|
|
|
|
}, |
900
|
|
|
|
|
|
|
"\$^T" => |
901
|
|
|
|
|
|
|
{ aliases => { "\$BASETIME" => 1 }, desc => "Program start time" }, |
902
|
|
|
|
|
|
|
"\$^V" => { |
903
|
|
|
|
|
|
|
aliases => { "\$PERL_VERSION" => 1 }, |
904
|
|
|
|
|
|
|
desc => "Perl interpreter version", |
905
|
|
|
|
|
|
|
}, |
906
|
|
|
|
|
|
|
"\$^W" => |
907
|
|
|
|
|
|
|
{ aliases => { "\$WARNING" => 1 }, desc => "Global warning flags" }, |
908
|
|
|
|
|
|
|
"\$^X" => { |
909
|
|
|
|
|
|
|
aliases => { "\$EXECUTABLE_NAME" => 1 }, |
910
|
|
|
|
|
|
|
desc => "Perl interpreter invocation name", |
911
|
|
|
|
|
|
|
}, |
912
|
|
|
|
|
|
|
"\$_" => { |
913
|
|
|
|
|
|
|
aliases => { "\$ARG" => 1 }, |
914
|
|
|
|
|
|
|
desc => |
915
|
|
|
|
|
|
|
"Topic variable: default argument for matches and many builtins", |
916
|
|
|
|
|
|
|
}, |
917
|
|
|
|
|
|
|
"\$`" => { |
918
|
|
|
|
|
|
|
aliases => { "\$PREMATCH" => 1 }, |
919
|
|
|
|
|
|
|
desc => "String preceding most recent regex match", |
920
|
|
|
|
|
|
|
}, |
921
|
|
|
|
|
|
|
"\$a" => { |
922
|
|
|
|
|
|
|
aliases => {}, |
923
|
|
|
|
|
|
|
desc => "Block parameter: automatically provided to sort blocks", |
924
|
|
|
|
|
|
|
}, |
925
|
|
|
|
|
|
|
"\$ACCUMULATOR" => { |
926
|
|
|
|
|
|
|
aliases => { "\$^A" => 1 }, |
927
|
|
|
|
|
|
|
desc => "Accumulator for format() lines", |
928
|
|
|
|
|
|
|
}, |
929
|
|
|
|
|
|
|
"\$ARG" => { |
930
|
|
|
|
|
|
|
aliases => { "\$_" => 1 }, |
931
|
|
|
|
|
|
|
desc => |
932
|
|
|
|
|
|
|
"Topic variable: default argument for matches and many builtins", |
933
|
|
|
|
|
|
|
}, |
934
|
|
|
|
|
|
|
"\$ARGV" => { |
935
|
|
|
|
|
|
|
aliases => {}, |
936
|
|
|
|
|
|
|
desc => "Name of file being read by readline() or <>", |
937
|
|
|
|
|
|
|
}, |
938
|
|
|
|
|
|
|
"\$ARRAY_BASE" => { |
939
|
|
|
|
|
|
|
aliases => { "\$[" => 1 }, |
940
|
|
|
|
|
|
|
desc => "Array index origin [deprecated]", |
941
|
|
|
|
|
|
|
}, |
942
|
|
|
|
|
|
|
"\$b" => { |
943
|
|
|
|
|
|
|
aliases => {}, |
944
|
|
|
|
|
|
|
desc => "Block parameter: automatically provided to sort blocks", |
945
|
|
|
|
|
|
|
}, |
946
|
|
|
|
|
|
|
"\$BASETIME" => |
947
|
|
|
|
|
|
|
{ aliases => { "\$^T" => 1 }, desc => "Program start time" }, |
948
|
|
|
|
|
|
|
"\$CHILD_ERROR" => { |
949
|
|
|
|
|
|
|
aliases => { "\$?" => 1 }, |
950
|
|
|
|
|
|
|
desc => "Status from most recent system call (including I/O)", |
951
|
|
|
|
|
|
|
}, |
952
|
|
|
|
|
|
|
"\$COMPILING" => { |
953
|
|
|
|
|
|
|
aliases => { "\$^C" => 1 }, |
954
|
|
|
|
|
|
|
desc => "Is the program still compiling?", |
955
|
|
|
|
|
|
|
}, |
956
|
|
|
|
|
|
|
"\$DEBUGGING" => |
957
|
|
|
|
|
|
|
{ aliases => { "\$^D" => 1 }, desc => "Debugging flags" }, |
958
|
|
|
|
|
|
|
"\$EFFECTIVE_GROUP_ID" => { |
959
|
|
|
|
|
|
|
aliases => { "\$)" => 1, "\$EGID" => 1 }, |
960
|
|
|
|
|
|
|
desc => "Effective group ID of the current process", |
961
|
|
|
|
|
|
|
}, |
962
|
|
|
|
|
|
|
"\$EFFECTIVE_USER_ID" => { |
963
|
|
|
|
|
|
|
aliases => { "\$>" => 1, "\$EUID" => 1 }, |
964
|
|
|
|
|
|
|
desc => "Effective uid of the current process", |
965
|
|
|
|
|
|
|
}, |
966
|
|
|
|
|
|
|
"\$EGID" => { |
967
|
|
|
|
|
|
|
aliases => { "\$)" => 1, "\$EFFECTIVE_GROUP_ID" => 1 }, |
968
|
|
|
|
|
|
|
desc => "Effective group ID of the current process", |
969
|
|
|
|
|
|
|
}, |
970
|
|
|
|
|
|
|
"\$ERRNO" => { |
971
|
|
|
|
|
|
|
aliases => { "\$!" => 1, "\$OS_ERROR" => 1 }, |
972
|
|
|
|
|
|
|
desc => "Status from most recent system call (including I/O)", |
973
|
|
|
|
|
|
|
}, |
974
|
|
|
|
|
|
|
"\$EUID" => { |
975
|
|
|
|
|
|
|
aliases => { "\$>" => 1, "\$EFFECTIVE_USER_ID" => 1 }, |
976
|
|
|
|
|
|
|
desc => "Effective uid of the current process", |
977
|
|
|
|
|
|
|
}, |
978
|
|
|
|
|
|
|
"\$EVAL_ERROR" => |
979
|
|
|
|
|
|
|
{ aliases => { "\$\@" => 1 }, desc => "Current propagating exception" }, |
980
|
|
|
|
|
|
|
"\$EXCEPTIONS_BEING_CAUGHT" => |
981
|
|
|
|
|
|
|
{ aliases => { "\$^S" => 1 }, desc => "Current eval() state" }, |
982
|
|
|
|
|
|
|
"\$EXECUTABLE_NAME" => { |
983
|
|
|
|
|
|
|
aliases => { "\$^X" => 1 }, |
984
|
|
|
|
|
|
|
desc => "Perl interpreter invocation name", |
985
|
|
|
|
|
|
|
}, |
986
|
|
|
|
|
|
|
"\$EXTENDED_OS_ERROR" => { |
987
|
|
|
|
|
|
|
aliases => { "\$^E" => 1 }, |
988
|
|
|
|
|
|
|
desc => "O/S specific error information", |
989
|
|
|
|
|
|
|
}, |
990
|
|
|
|
|
|
|
"\$FORMAT_FORMFEED" => { |
991
|
|
|
|
|
|
|
aliases => { "\$^L" => 1 }, |
992
|
|
|
|
|
|
|
desc => "Form-feed sequence for format() pages", |
993
|
|
|
|
|
|
|
}, |
994
|
|
|
|
|
|
|
"\$FORMAT_LINE_BREAK_CHARACTERS" => { |
995
|
|
|
|
|
|
|
aliases => { "\$:" => 1 }, |
996
|
|
|
|
|
|
|
desc => "Break characters for format() lines", |
997
|
|
|
|
|
|
|
}, |
998
|
|
|
|
|
|
|
"\$FORMAT_LINES_LEFT" => { |
999
|
|
|
|
|
|
|
aliases => { "\$-" => 1 }, |
1000
|
|
|
|
|
|
|
desc => "Number of lines remaining in current output page", |
1001
|
|
|
|
|
|
|
}, |
1002
|
|
|
|
|
|
|
"\$FORMAT_LINES_PER_PAGE" => { |
1003
|
|
|
|
|
|
|
aliases => { "\$=" => 1 }, |
1004
|
|
|
|
|
|
|
desc => "Page length of selected output channel", |
1005
|
|
|
|
|
|
|
}, |
1006
|
|
|
|
|
|
|
"\$FORMAT_NAME" => { |
1007
|
|
|
|
|
|
|
aliases => { "\$~" => 1 }, |
1008
|
|
|
|
|
|
|
desc => "Name of format for selected output channel", |
1009
|
|
|
|
|
|
|
}, |
1010
|
|
|
|
|
|
|
"\$FORMAT_PAGE_NUMBER" => { |
1011
|
|
|
|
|
|
|
aliases => { "\$%" => 1 }, |
1012
|
|
|
|
|
|
|
desc => "Page number of the current output page", |
1013
|
|
|
|
|
|
|
}, |
1014
|
|
|
|
|
|
|
"\$FORMAT_TOP_NAME" => { |
1015
|
|
|
|
|
|
|
aliases => { "\$^" => 1 }, |
1016
|
|
|
|
|
|
|
desc => "Name of top-of-page format for selected output channel", |
1017
|
|
|
|
|
|
|
}, |
1018
|
|
|
|
|
|
|
"\$GID" => { |
1019
|
|
|
|
|
|
|
aliases => { "\$(" => 1, "\$REAL_GROUP_ID" => 1 }, |
1020
|
|
|
|
|
|
|
desc => "Real group ID of the current process", |
1021
|
|
|
|
|
|
|
}, |
1022
|
|
|
|
|
|
|
"\$INPLACE_EDIT" => |
1023
|
|
|
|
|
|
|
{ aliases => { "\$^I" => 1 }, desc => "In-place editing value" }, |
1024
|
|
|
|
|
|
|
"\$INPUT_LINE_NUMBER" => { |
1025
|
|
|
|
|
|
|
aliases => { "\$." => 1, "\$NR" => 1 }, |
1026
|
|
|
|
|
|
|
desc => "Line number of last input line", |
1027
|
|
|
|
|
|
|
}, |
1028
|
|
|
|
|
|
|
"\$INPUT_RECORD_SEPARATOR" => { |
1029
|
|
|
|
|
|
|
aliases => { "\$/" => 1, "\$RS" => 1 }, |
1030
|
|
|
|
|
|
|
desc => "Input record separator (end-of-line marker on inputs)", |
1031
|
|
|
|
|
|
|
}, |
1032
|
|
|
|
|
|
|
"\$LAST_PAREN_MATCH" => { |
1033
|
|
|
|
|
|
|
aliases => { "\$+" => 1 }, |
1034
|
|
|
|
|
|
|
desc => "Final capture group of most recent regex match", |
1035
|
|
|
|
|
|
|
}, |
1036
|
|
|
|
|
|
|
"\$LAST_REGEXP_CODE_RESULT" => { |
1037
|
|
|
|
|
|
|
aliases => { "\$^R" => 1 }, |
1038
|
|
|
|
|
|
|
desc => "Result of last successful code block (within regex)", |
1039
|
|
|
|
|
|
|
}, |
1040
|
|
|
|
|
|
|
"\$LAST_SUBMATCH_RESULT" => { |
1041
|
|
|
|
|
|
|
aliases => { "\$^N" => 1 }, |
1042
|
|
|
|
|
|
|
desc => "Most recent capture group (within regex)", |
1043
|
|
|
|
|
|
|
}, |
1044
|
|
|
|
|
|
|
"\$LIST_SEPARATOR" => { |
1045
|
|
|
|
|
|
|
aliases => { "\$\"" => 1 }, |
1046
|
|
|
|
|
|
|
desc => "List separator for array interpolation", |
1047
|
|
|
|
|
|
|
}, |
1048
|
|
|
|
|
|
|
"\$MATCH" => |
1049
|
|
|
|
|
|
|
{ aliases => { "\$&" => 1 }, desc => "Most recent regex match string" }, |
1050
|
|
|
|
|
|
|
"\$NR" => { |
1051
|
|
|
|
|
|
|
aliases => { "\$." => 1, "\$INPUT_LINE_NUMBER" => 1 }, |
1052
|
|
|
|
|
|
|
desc => "Line number of last input line", |
1053
|
|
|
|
|
|
|
}, |
1054
|
|
|
|
|
|
|
"\$OFMT" => { |
1055
|
|
|
|
|
|
|
aliases => { "\$#" => 1 }, |
1056
|
|
|
|
|
|
|
desc => "Output number format [deprecated: use printf() instead]", |
1057
|
|
|
|
|
|
|
}, |
1058
|
|
|
|
|
|
|
"\$OFS" => { |
1059
|
|
|
|
|
|
|
aliases => { "\$," => 1, "\$OUTPUT_FIELD_SEPARATOR" => 1 }, |
1060
|
|
|
|
|
|
|
desc => "Output field separator for print() and say()", |
1061
|
|
|
|
|
|
|
}, |
1062
|
|
|
|
|
|
|
"\$ORS" => { |
1063
|
|
|
|
|
|
|
aliases => { "\$\\" => 1, "\$OUTPUT_RECORD_SEPARATOR" => 1 }, |
1064
|
|
|
|
|
|
|
desc => "Output record separator (appended to every print())", |
1065
|
|
|
|
|
|
|
}, |
1066
|
|
|
|
|
|
|
"\$OS_ERROR" => { |
1067
|
|
|
|
|
|
|
aliases => { "\$!" => 1, "\$ERRNO" => 1 }, |
1068
|
|
|
|
|
|
|
desc => "Status from most recent system call (including I/O)", |
1069
|
|
|
|
|
|
|
}, |
1070
|
|
|
|
|
|
|
"\$OSNAME" => |
1071
|
|
|
|
|
|
|
{ aliases => { "\$^O" => 1 }, desc => "Operating system name" }, |
1072
|
|
|
|
|
|
|
"\$OUTPUT_AUTOFLUSH" => { |
1073
|
|
|
|
|
|
|
aliases => { "\$|" => 1 }, |
1074
|
|
|
|
|
|
|
desc => "Autoflush status of selected output filehandle", |
1075
|
|
|
|
|
|
|
}, |
1076
|
|
|
|
|
|
|
"\$OUTPUT_FIELD_SEPARATOR" => { |
1077
|
|
|
|
|
|
|
aliases => { "\$," => 1, "\$OFS" => 1 }, |
1078
|
|
|
|
|
|
|
desc => "Output field separator for print() and say()", |
1079
|
|
|
|
|
|
|
}, |
1080
|
|
|
|
|
|
|
"\$OUTPUT_RECORD_SEPARATOR" => { |
1081
|
|
|
|
|
|
|
aliases => { "\$\\" => 1, "\$ORS" => 1 }, |
1082
|
|
|
|
|
|
|
desc => "Output record separator (appended to every print())", |
1083
|
|
|
|
|
|
|
}, |
1084
|
|
|
|
|
|
|
"\$PERL_VERSION" => |
1085
|
|
|
|
|
|
|
{ aliases => { "\$^V" => 1 }, desc => "Perl interpreter version" }, |
1086
|
|
|
|
|
|
|
"\$PERLDB" => |
1087
|
|
|
|
|
|
|
{ aliases => { "\$^P" => 1 }, desc => "Internal debugging flags" }, |
1088
|
|
|
|
|
|
|
"\$PID" => { |
1089
|
|
|
|
|
|
|
aliases => { "\$\$" => 1, "\$PROCESS_ID" => 1 }, |
1090
|
|
|
|
|
|
|
desc => "Process ID", |
1091
|
|
|
|
|
|
|
}, |
1092
|
|
|
|
|
|
|
"\$POSTMATCH" => { |
1093
|
|
|
|
|
|
|
aliases => { "\$'" => 1 }, |
1094
|
|
|
|
|
|
|
desc => "String following most recent regex match", |
1095
|
|
|
|
|
|
|
}, |
1096
|
|
|
|
|
|
|
"\$PREMATCH" => { |
1097
|
|
|
|
|
|
|
aliases => { "\$`" => 1 }, |
1098
|
|
|
|
|
|
|
desc => "String preceding most recent regex match", |
1099
|
|
|
|
|
|
|
}, |
1100
|
|
|
|
|
|
|
"\$PROCESS_ID" => |
1101
|
|
|
|
|
|
|
{ aliases => { "\$\$" => 1, "\$PID" => 1 }, desc => "Process ID" }, |
1102
|
|
|
|
|
|
|
"\$PROGRAM_NAME" => { aliases => { "\$0" => 1 }, desc => "Program name" }, |
1103
|
|
|
|
|
|
|
"\$REAL_GROUP_ID" => { |
1104
|
|
|
|
|
|
|
aliases => { "\$(" => 1, "\$GID" => 1 }, |
1105
|
|
|
|
|
|
|
desc => "Real group ID of the current process", |
1106
|
|
|
|
|
|
|
}, |
1107
|
|
|
|
|
|
|
"\$REAL_USER_ID" => { |
1108
|
|
|
|
|
|
|
aliases => { "\$<" => 1, "\$UID" => 1 }, |
1109
|
|
|
|
|
|
|
desc => "Real uid of the current process", |
1110
|
|
|
|
|
|
|
}, |
1111
|
|
|
|
|
|
|
"\$RS" => { |
1112
|
|
|
|
|
|
|
aliases => { "\$/" => 1, "\$INPUT_RECORD_SEPARATOR" => 1 }, |
1113
|
|
|
|
|
|
|
desc => "Input record separator (end-of-line marker on inputs)", |
1114
|
|
|
|
|
|
|
}, |
1115
|
|
|
|
|
|
|
"\$SUBSCRIPT_SEPARATOR" => { |
1116
|
|
|
|
|
|
|
aliases => { "\$;" => 1, "\$SUBSEP" => 1 }, |
1117
|
|
|
|
|
|
|
desc => "Hash subscript separator for key concatenation", |
1118
|
|
|
|
|
|
|
}, |
1119
|
|
|
|
|
|
|
"\$SUBSEP" => { |
1120
|
|
|
|
|
|
|
aliases => { "\$;" => 1, "\$SUBSCRIPT_SEPARATOR" => 1 }, |
1121
|
|
|
|
|
|
|
desc => "Hash subscript separator for key concatenation", |
1122
|
|
|
|
|
|
|
}, |
1123
|
|
|
|
|
|
|
"\$SYSTEM_FD_MAX" => { |
1124
|
|
|
|
|
|
|
aliases => { "\$^F" => 1 }, |
1125
|
|
|
|
|
|
|
desc => "Maximum system file descriptor", |
1126
|
|
|
|
|
|
|
}, |
1127
|
|
|
|
|
|
|
"\$UID" => { |
1128
|
|
|
|
|
|
|
aliases => { "\$<" => 1, "\$REAL_USER_ID" => 1 }, |
1129
|
|
|
|
|
|
|
desc => "Real uid of the current process", |
1130
|
|
|
|
|
|
|
}, |
1131
|
|
|
|
|
|
|
"\$WARNING" => |
1132
|
|
|
|
|
|
|
{ aliases => { "\$^W" => 1 }, desc => "Global warning flags" }, |
1133
|
|
|
|
|
|
|
"\${^CHILD_ERROR_NATIVE}" => { |
1134
|
|
|
|
|
|
|
aliases => {}, |
1135
|
|
|
|
|
|
|
desc => "Native status from most recent system-level call", |
1136
|
|
|
|
|
|
|
}, |
1137
|
|
|
|
|
|
|
"\${^ENCODING}" => { |
1138
|
|
|
|
|
|
|
aliases => {}, |
1139
|
|
|
|
|
|
|
desc => "Encode object for source conversion to Unicode", |
1140
|
|
|
|
|
|
|
}, |
1141
|
|
|
|
|
|
|
"\${^GLOBAL_PHASE}" => |
1142
|
|
|
|
|
|
|
{ aliases => {}, desc => "Current interpreter phase" }, |
1143
|
|
|
|
|
|
|
"\${^MATCH}" => |
1144
|
|
|
|
|
|
|
{ aliases => {}, desc => "Most recent regex match string (under /p)" }, |
1145
|
|
|
|
|
|
|
"\${^OPEN}" => { aliases => {}, desc => "PerlIO I/O layers" }, |
1146
|
|
|
|
|
|
|
"\${^POSTMATCH}" => { |
1147
|
|
|
|
|
|
|
aliases => {}, |
1148
|
|
|
|
|
|
|
desc => "String following most recent regex match (under /p)", |
1149
|
|
|
|
|
|
|
}, |
1150
|
|
|
|
|
|
|
"\${^PREMATCH}" => { |
1151
|
|
|
|
|
|
|
aliases => {}, |
1152
|
|
|
|
|
|
|
desc => "String preceding most recent regex match (under /p)", |
1153
|
|
|
|
|
|
|
}, |
1154
|
|
|
|
|
|
|
"\${^RE_DEBUG_FLAGS}" => |
1155
|
|
|
|
|
|
|
{ aliases => {}, desc => "Regex debugging flags" }, |
1156
|
|
|
|
|
|
|
"\${^RE_TRIE_MAXBUF}" => |
1157
|
|
|
|
|
|
|
{ aliases => {}, desc => "Cache limit on regex optimizations" }, |
1158
|
|
|
|
|
|
|
"\${^TAINT}" => { aliases => {}, desc => "Taint mode" }, |
1159
|
|
|
|
|
|
|
"\${^UNICODE}" => { aliases => {}, desc => "Unicode settings" }, |
1160
|
|
|
|
|
|
|
"\${^UTF8CACHE}" => |
1161
|
|
|
|
|
|
|
{ aliases => {}, desc => "Internal UTF-8 offset caching controls" }, |
1162
|
|
|
|
|
|
|
"\${^UTF8LOCALE}" => { aliases => {}, desc => "UTF-8 locale" }, |
1163
|
|
|
|
|
|
|
"\${^WARNING_BITS}" => { aliases => {}, desc => "Lexical warning flags" }, |
1164
|
|
|
|
|
|
|
"\${^WIN32_SLOPPY_STAT}" => |
1165
|
|
|
|
|
|
|
{ aliases => {}, desc => "Use non-opening stat() under Windows" }, |
1166
|
|
|
|
|
|
|
"\$|" => { |
1167
|
|
|
|
|
|
|
aliases => { "\$OUTPUT_AUTOFLUSH" => 1 }, |
1168
|
|
|
|
|
|
|
desc => "Autoflush status of selected output filehandle", |
1169
|
|
|
|
|
|
|
}, |
1170
|
|
|
|
|
|
|
"\$~" => { |
1171
|
|
|
|
|
|
|
aliases => { "\$FORMAT_NAME" => 1 }, |
1172
|
|
|
|
|
|
|
desc => "Name of format for selected output channel", |
1173
|
|
|
|
|
|
|
}, |
1174
|
|
|
|
|
|
|
"%!" => { |
1175
|
|
|
|
|
|
|
aliases => { "%ERRNO" => 1, "%OS_ERROR" => 1 }, |
1176
|
|
|
|
|
|
|
desc => "Status of all possible errors from most recent system call", |
1177
|
|
|
|
|
|
|
}, |
1178
|
|
|
|
|
|
|
"%+" => { |
1179
|
|
|
|
|
|
|
aliases => {}, |
1180
|
|
|
|
|
|
|
desc => "Named captures of most recent regex match (as strings)", |
1181
|
|
|
|
|
|
|
}, |
1182
|
|
|
|
|
|
|
"%-" => { |
1183
|
|
|
|
|
|
|
aliases => { "%LAST_MATCH_START" => 1 }, |
1184
|
|
|
|
|
|
|
desc => |
1185
|
|
|
|
|
|
|
"Named captures of most recent regex match (as arrays of strings)", |
1186
|
|
|
|
|
|
|
}, |
1187
|
|
|
|
|
|
|
"%^H" => { aliases => {}, desc => "Lexical hints hash" }, |
1188
|
|
|
|
|
|
|
"%ENV" => { aliases => {}, desc => "The current shell environment" }, |
1189
|
|
|
|
|
|
|
"%ERRNO" => { |
1190
|
|
|
|
|
|
|
aliases => { "%!" => 1, "%OS_ERROR" => 1 }, |
1191
|
|
|
|
|
|
|
desc => "Status of all possible errors from most recent system call", |
1192
|
|
|
|
|
|
|
}, |
1193
|
|
|
|
|
|
|
"%INC" => { aliases => {}, desc => "Filepaths of loaded modules" }, |
1194
|
|
|
|
|
|
|
"%LAST_MATCH_START" => { |
1195
|
|
|
|
|
|
|
aliases => { "%-" => 1 }, |
1196
|
|
|
|
|
|
|
desc => |
1197
|
|
|
|
|
|
|
"Named captures of most recent regex match (as arrays of strings)", |
1198
|
|
|
|
|
|
|
}, |
1199
|
|
|
|
|
|
|
"%OS_ERROR" => { |
1200
|
|
|
|
|
|
|
aliases => { "%!" => 1, "%ERRNO" => 1 }, |
1201
|
|
|
|
|
|
|
desc => "Status of all possible errors from most recent system call", |
1202
|
|
|
|
|
|
|
}, |
1203
|
|
|
|
|
|
|
"%SIG" => { aliases => {}, desc => "Signal handlers" }, |
1204
|
|
|
|
|
|
|
"\@+" => { |
1205
|
|
|
|
|
|
|
aliases => { "\@LAST_PAREN_MATCH" => 1 }, |
1206
|
|
|
|
|
|
|
desc => |
1207
|
|
|
|
|
|
|
"Offsets of ends of capture groups of most recent regex match", |
1208
|
|
|
|
|
|
|
}, |
1209
|
|
|
|
|
|
|
"\@-" => { |
1210
|
|
|
|
|
|
|
aliases => { "\@LAST_MATCH_START" => 1 }, |
1211
|
|
|
|
|
|
|
desc => |
1212
|
|
|
|
|
|
|
"Offsets of starts of capture groups of most recent regex match", |
1213
|
|
|
|
|
|
|
}, |
1214
|
|
|
|
|
|
|
"\@_" => { aliases => { "\@ARG" => 1 }, desc => "Subroutine arguments" }, |
1215
|
|
|
|
|
|
|
"\@ARG" => { aliases => { "\@_" => 1 }, desc => "Subroutine arguments" }, |
1216
|
|
|
|
|
|
|
"\@ARGV" => { aliases => {}, desc => "Command line arguments" }, |
1217
|
|
|
|
|
|
|
"\@F" => { |
1218
|
|
|
|
|
|
|
aliases => {}, |
1219
|
|
|
|
|
|
|
desc => "Fields of the current input line (under autosplit mode)", |
1220
|
|
|
|
|
|
|
}, |
1221
|
|
|
|
|
|
|
"\@INC" => { aliases => {}, desc => "Search path for loading modules" }, |
1222
|
|
|
|
|
|
|
"\@LAST_MATCH_START" => { |
1223
|
|
|
|
|
|
|
aliases => { "\@-" => 1 }, |
1224
|
|
|
|
|
|
|
desc => |
1225
|
|
|
|
|
|
|
"Offsets of starts of capture groups of most recent regex match", |
1226
|
|
|
|
|
|
|
}, |
1227
|
|
|
|
|
|
|
"\@LAST_PAREN_MATCH" => { |
1228
|
|
|
|
|
|
|
aliases => { "\@+" => 1 }, |
1229
|
|
|
|
|
|
|
desc => |
1230
|
|
|
|
|
|
|
"Offsets of ends of capture groups of most recent regex match", |
1231
|
|
|
|
|
|
|
}, |
1232
|
|
|
|
|
|
|
); |
1233
|
|
|
|
|
|
|
|
1234
|
|
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
# Build pattern to detect "unhelpful" variable and subroutine names |
1236
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
my @CACOGRAMS = qw< |
1238
|
|
|
|
|
|
|
in(put) |
1239
|
|
|
|
|
|
|
out(put) |
1240
|
|
|
|
|
|
|
get |
1241
|
|
|
|
|
|
|
put |
1242
|
|
|
|
|
|
|
(re)set |
1243
|
|
|
|
|
|
|
clear |
1244
|
|
|
|
|
|
|
update |
1245
|
|
|
|
|
|
|
|
1246
|
|
|
|
|
|
|
array |
1247
|
|
|
|
|
|
|
data |
1248
|
|
|
|
|
|
|
dict(ionary) |
1249
|
|
|
|
|
|
|
dictionaries |
1250
|
|
|
|
|
|
|
elem(ent) |
1251
|
|
|
|
|
|
|
hash |
1252
|
|
|
|
|
|
|
heap |
1253
|
|
|
|
|
|
|
idx |
1254
|
|
|
|
|
|
|
indices |
1255
|
|
|
|
|
|
|
key[] |
1256
|
|
|
|
|
|
|
list |
1257
|
|
|
|
|
|
|
node |
1258
|
|
|
|
|
|
|
num(ber) |
1259
|
|
|
|
|
|
|
obj(ect) |
1260
|
|
|
|
|
|
|
queue |
1261
|
|
|
|
|
|
|
rec(ord) |
1262
|
|
|
|
|
|
|
scalar |
1263
|
|
|
|
|
|
|
set |
1264
|
|
|
|
|
|
|
stack |
1265
|
|
|
|
|
|
|
str(ing) |
1266
|
|
|
|
|
|
|
tree |
1267
|
|
|
|
|
|
|
val(ue)[] |
1268
|
|
|
|
|
|
|
opt(ion) |
1269
|
|
|
|
|
|
|
arg(ument) |
1270
|
|
|
|
|
|
|
range |
1271
|
|
|
|
|
|
|
var(iable) |
1272
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
desc(riptor) |
1274
|
|
|
|
|
|
|
alt(ernate) |
1275
|
|
|
|
|
|
|
item |
1276
|
|
|
|
|
|
|
prev(ious) |
1277
|
|
|
|
|
|
|
next |
1278
|
|
|
|
|
|
|
last |
1279
|
|
|
|
|
|
|
other |
1280
|
|
|
|
|
|
|
res(ult) |
1281
|
|
|
|
|
|
|
target |
1282
|
|
|
|
|
|
|
name |
1283
|
|
|
|
|
|
|
count |
1284
|
|
|
|
|
|
|
size |
1285
|
|
|
|
|
|
|
optional |
1286
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
foo |
1288
|
500
|
|
|
500
|
|
726
|
bar |
1289
|
|
|
|
|
|
|
baz |
1290
|
500
|
|
|
|
|
722
|
>; |
1291
|
500
|
|
|
|
|
873
|
|
1292
|
500
|
|
|
|
|
892
|
sub _inflect { |
1293
|
|
|
|
|
|
|
my ($word) = @_; |
1294
|
500
|
|
|
|
|
1207
|
|
1295
|
500
|
|
100
|
|
|
1508
|
my $singular = $word =~ s{ \[ .* \]}{}rxms; |
|
500
|
|
|
|
|
2084
|
|
1296
|
|
|
|
|
|
|
my $sing = $singular =~ s{ \( .* \) }{}grxms; |
1297
|
|
|
|
|
|
|
$singular =~ s/[()]//g; |
1298
|
500
|
|
|
|
|
2752
|
|
1299
|
|
|
|
|
|
|
my $plur = ($word =~ s{ \( .* \) | \[ .* \]}{}grxms) .'s'; |
1300
|
|
|
|
|
|
|
my $plural = $word =~ s{ \[ (.*?) \] | \Z }{ $1 // 's'}erxms |
1301
|
|
|
|
|
|
|
=~ s{ [()] }{}grxms; |
1302
|
|
|
|
|
|
|
|
1303
|
|
|
|
|
|
|
return $plural, $plur, $singular, $sing; |
1304
|
|
|
|
|
|
|
} |
1305
|
|
|
|
|
|
|
|
1306
|
|
|
|
|
|
|
my $CACOGRAMS_PAT |
1307
|
|
|
|
|
|
|
= '\b(?!_\z)(?:'.join('|', reverse(sort(uniq(map { _inflect($_) } @CACOGRAMS, '_')))).')+\b'; |
1308
|
|
|
|
|
|
|
|
1309
|
|
|
|
|
|
|
|
1310
|
|
|
|
|
|
|
# Build tools to detect parograms (similar, but not identical variable and sub names)... |
1311
|
|
|
|
|
|
|
|
1312
|
|
|
|
|
|
|
my $VOWEL = '[aeiou]'; |
1313
|
|
|
|
|
|
|
my @DOUBLE_CONSONANT |
1314
|
|
|
|
|
|
|
= map {("$_$_(?=$VOWEL)" => { "$_$_" => "$_$_?", $_ => "$_$_?" }, |
1315
|
|
|
|
|
|
|
"(?<=$VOWEL)$_(?=$VOWEL)" => { "$_$_" => "$_$_?", $_ => "$_$_?" }, |
1316
|
|
|
|
|
|
|
)} |
1317
|
|
|
|
|
|
|
qw< b c d f g h j k l m n p q r s t v w x y z >; |
1318
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
my %VARIANT_SPELLING = ( |
1320
|
|
|
|
|
|
|
'ou?r' => { or => 'ou?r', our => 'ou?r', }, |
1321
|
|
|
|
|
|
|
'en[cs](?=e)' => { enc => 'en[cs]', ens => 'en[cs]', }, |
1322
|
|
|
|
|
|
|
'\B(?:er|re)' => { er => '(?:er|re)', re => '(?:er|re)', }, |
1323
|
|
|
|
|
|
|
'(?:x|ct)ion' => { xion => '(?:x|ct)ion', ction => '(?:x|ct)ion', }, |
1324
|
|
|
|
|
|
|
'ae' => { ae => 'a?e', }, |
1325
|
|
|
|
|
|
|
'oe' => { oe => 'o?e', }, |
1326
|
|
|
|
|
|
|
'i[sz](?=e)' => { is => 'i[sz]', iz => 'i[sz]', }, |
1327
|
|
|
|
|
|
|
'y[sz](?=e)' => { ys => 'y[sz]', yz => 'y[sz]', }, |
1328
|
|
|
|
|
|
|
'og(?:ue)?' => { og => 'og(?:ue)?', ogue => 'og(?:ue)?', }, |
1329
|
|
|
|
|
|
|
'e?abl' => { eabl => 'e?abl', abl => 'e?abl', }, |
1330
|
|
|
|
|
|
|
@DOUBLE_CONSONANT, |
1331
|
|
|
|
|
|
|
); |
1332
|
|
|
|
|
|
|
my %VARIANT_PAT = map { %{$_}; } values %VARIANT_SPELLING; |
1333
|
|
|
|
|
|
|
my $VARIANT_SPELLING = join('|', reverse sort keys %VARIANT_SPELLING); |
1334
|
|
|
|
|
|
|
|
1335
|
|
|
|
|
|
|
my @CONFLATION_GROUPS = ('aeiou', 'bdfhklt', 'cmnrsvwxz', 'gjpqy'); |
1336
|
|
|
|
|
|
|
my %CONFLATION_CHARS; |
1337
|
|
|
|
|
|
|
for my $group (@CONFLATION_GROUPS) { |
1338
|
|
|
|
|
|
|
for my $letter (split('', $group)) { |
1339
|
843
|
|
|
843
|
|
1391
|
$CONFLATION_CHARS{$letter} = "[$group]" =~ s/$letter//gr; |
1340
|
|
|
|
|
|
|
} |
1341
|
|
|
|
|
|
|
} |
1342
|
843
|
|
|
|
|
1779
|
|
|
3658
|
|
|
|
|
4429
|
|
1343
|
3658
|
100
|
66
|
|
|
6527
|
sub _parograms_of { |
|
3658
|
|
|
|
|
14706
|
|
|
10637
|
|
|
|
|
26782
|
|
1344
|
|
|
|
|
|
|
my ($word) = @_; |
1345
|
|
|
|
|
|
|
|
1346
|
|
|
|
|
|
|
my $typos = join '|', |
1347
|
843
|
|
33
|
|
|
9859
|
map { our $pos = $_; |
|
605
|
|
|
|
|
5980
|
|
1348
|
|
|
|
|
|
|
$word =~ s{(??{pos==$pos?'':'(?!)'}) .}{$CONFLATION_CHARS{$&} // $&}eixmsr; |
1349
|
843
|
100
|
|
|
|
2939
|
} |
1350
|
|
|
|
|
|
|
0..length($word)-1; |
1351
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
my $spelling = $word =~ s{$VARIANT_SPELLING}{$VARIANT_PAT{lc $&}//$&}egixmsr; |
1353
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
return $spelling ne $word ? "(?i:$spelling|$typos)" : "(?i:$typos)"; |
1355
|
14480
|
|
|
14480
|
|
18128
|
} |
1356
|
14480
|
|
|
|
|
18810
|
|
1357
|
14480
|
|
|
|
|
15980
|
|
1358
|
14480
|
|
|
|
|
36374
|
# Determine if two variables overlap in scope... |
1359
|
|
|
|
|
|
|
sub _share_scope { |
1360
|
|
|
|
|
|
|
my ($var1, $var2) = @_; |
1361
|
|
|
|
|
|
|
my $from_delta = $var1->{start_of_scope} - $var2->{start_of_scope}; |
1362
|
|
|
|
|
|
|
my $to_delta = $var1->{end_of_scope} - $var2->{end_of_scope}; |
1363
|
57
|
|
|
57
|
0
|
192
|
return $from_delta * $to_delta <= 0; |
1364
|
|
|
|
|
|
|
} |
1365
|
|
|
|
|
|
|
|
1366
|
10
|
|
|
10
|
|
104
|
# Locate all mentions of all variable in the specified code... |
|
10
|
|
|
|
|
26
|
|
|
10
|
|
|
|
|
18172
|
|
1367
|
57
|
|
|
|
|
395
|
sub classify_all_vars_in { |
1368
|
|
|
|
|
|
|
my ($source) = @_; |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
# A stack to track the scope of each variable |
1371
|
57
|
|
|
|
|
200
|
no warnings 'once'; |
1372
|
57
|
|
|
|
|
180
|
local @Code::ART::varscope = { ids => {}, decls => [] }; |
1373
|
57
|
|
|
|
|
144
|
|
1374
|
|
|
|
|
|
|
# Hashes to track their variable descriptions and uses |
1375
|
|
|
|
|
|
|
# (Variables are identified by the offset of their declaration from the start of the source)... |
1376
|
57
|
|
|
|
|
368558
|
local %Code::ART::varinfo = (); |
1377
|
|
|
|
|
|
|
local %Code::ART::varuse = (); |
1378
|
|
|
|
|
|
|
local $Code::ART::use_version = 0; |
1379
|
|
|
|
|
|
|
|
1380
|
|
|
|
|
|
|
# Detect and record all instances of variable within the source code... |
1381
|
|
|
|
|
|
|
my $matched = $source =~ m{ |
1382
|
|
|
|
|
|
|
\A |
1383
|
|
|
|
|
|
|
(?&_push_scope) |
1384
|
|
|
|
|
|
|
(?&PerlDocument) |
1385
|
|
|
|
|
|
|
(?&_pop_scope) |
1386
|
|
|
|
|
|
|
\Z |
1387
|
|
|
|
|
|
|
|
1388
|
5
|
|
|
|
|
253
|
(?(DEFINE) |
1389
|
|
|
|
|
|
|
(? |
1390
|
|
|
|
|
|
|
(?> |
1391
|
|
|
|
|
|
|
use (?>(?&PerlOWS)) |
1392
|
|
|
|
|
|
|
(? \d++ (?: \. \d++)?+ | v\d++ (?: \. \d++)*+ ) |
1393
|
|
|
|
|
|
|
(?{ $Code::ART::use_version = version->parse("$+{version}") }) |
1394
|
|
|
|
|
|
|
| |
1395
|
|
|
|
|
|
|
(?&PerlStdUseStatement) |
1396
|
|
|
|
|
|
|
) |
1397
|
|
|
|
|
|
|
) |
1398
|
|
|
|
|
|
|
|
1399
|
|
|
|
|
|
|
(? |
1400
|
|
|
|
|
|
|
(?> |
1401
|
|
|
|
|
|
|
(?&_push_scope) |
1402
|
|
|
|
|
|
|
(?&PerlStdBlock) |
1403
|
|
|
|
|
|
|
(?&_pop_scope) |
1404
|
|
|
|
|
|
|
| |
1405
|
|
|
|
|
|
|
(?&_revert_scope_on_failure) |
1406
|
|
|
|
|
|
|
) |
1407
|
|
|
|
|
|
|
) |
1408
|
|
|
|
|
|
|
|
1409
|
|
|
|
|
|
|
(? |
1410
|
|
|
|
|
|
|
(?> |
1411
|
|
|
|
|
|
|
(?&_push_scope) |
1412
|
|
|
|
|
|
|
(?&PerlStdAnonymousHash) |
1413
|
|
|
|
|
|
|
(?&_pop_scope) |
1414
|
|
|
|
|
|
|
| |
1415
|
|
|
|
|
|
|
(?&_revert_scope_on_failure) |
1416
|
|
|
|
|
|
|
) |
1417
|
|
|
|
|
|
|
) |
1418
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
(? |
1420
|
|
|
|
|
|
|
(?> |
1421
|
|
|
|
|
|
|
(?&PerlStdStatement) |
1422
|
|
|
|
|
|
|
(?&_install_pending_decls) |
1423
|
|
|
|
|
|
|
| |
1424
|
|
|
|
|
|
|
(?&_clear_pending_declaration) |
1425
|
|
|
|
|
|
|
) |
1426
|
|
|
|
|
|
|
) |
1427
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
(? |
1429
|
|
|
|
|
|
|
(?&_push_scope) |
1430
|
|
|
|
|
|
|
(?> |
1431
|
|
|
|
|
|
|
# Conditionals can have var declarations in their conditions... |
1432
|
|
|
|
|
|
|
(?> if | unless ) \b (?>(?&PerlOWS)) |
1433
|
|
|
|
|
|
|
(?>(?&PerlParenthesesList)) (?>(?&PerlOWS)) |
1434
|
|
|
|
|
|
|
(?= [^\n]* |
1435
|
|
|
|
|
|
|
(?
|
1436
|
|
|
|
|
|
|
(?
|
1437
|
|
|
|
|
|
|
\h* \# \h* |
1438
|
|
|
|
|
|
|
(? [^\n]* ) |
1439
|
|
|
|
|
|
|
| |
1440
|
|
|
|
|
|
|
(?) |
1441
|
|
|
|
|
|
|
) |
1442
|
|
|
|
|
|
|
(?&_install_pending_decls) |
1443
|
|
|
|
|
|
|
(?>(?&PerlBlock)) |
1444
|
|
|
|
|
|
|
(?&_pop_scope) |
1445
|
|
|
|
|
|
|
|
1446
|
|
|
|
|
|
|
(?: |
1447
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
1448
|
|
|
|
|
|
|
(?>(?&PerlPodSequence)) |
1449
|
|
|
|
|
|
|
elsif \b (?>(?&PerlOWS)) |
1450
|
|
|
|
|
|
|
(?> |
1451
|
|
|
|
|
|
|
(?&_push_scope) |
1452
|
|
|
|
|
|
|
(?>(?&PerlParenthesesList)) (?>(?&PerlOWS)) |
1453
|
|
|
|
|
|
|
(?= [^\n]* |
1454
|
|
|
|
|
|
|
(?
|
1455
|
|
|
|
|
|
|
(?
|
1456
|
|
|
|
|
|
|
\h* \# \h* |
1457
|
|
|
|
|
|
|
(? [^\n]* ) |
1458
|
|
|
|
|
|
|
| |
1459
|
|
|
|
|
|
|
(?) |
1460
|
|
|
|
|
|
|
) |
1461
|
|
|
|
|
|
|
(?&_install_pending_decls) |
1462
|
|
|
|
|
|
|
(?&PerlBlock) |
1463
|
|
|
|
|
|
|
(?&_pop_scope) |
1464
|
|
|
|
|
|
|
| |
1465
|
|
|
|
|
|
|
(?&_revert_scope_on_failure) |
1466
|
|
|
|
|
|
|
) |
1467
|
|
|
|
|
|
|
)*+ |
1468
|
|
|
|
|
|
|
|
1469
|
|
|
|
|
|
|
(?: |
1470
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
1471
|
|
|
|
|
|
|
(?>(?&PerlPodSequence)) |
1472
|
|
|
|
|
|
|
else \b (?>(?&PerlOWS)) |
1473
|
|
|
|
|
|
|
(?&PerlBlock) |
1474
|
|
|
|
|
|
|
)?+ |
1475
|
|
|
|
|
|
|
| |
1476
|
|
|
|
|
|
|
# Have to handle loops specially (may have var declarations)... |
1477
|
|
|
|
|
|
|
(?> |
1478
|
|
|
|
|
|
|
(? for(?:each)?+ \b ) |
1479
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
1480
|
|
|
|
|
|
|
(?> |
1481
|
|
|
|
|
|
|
(?&_allow_decls) |
1482
|
|
|
|
|
|
|
(?> # Explicitly aliased iterator variable... |
1483
|
|
|
|
|
|
|
(?> |
1484
|
|
|
|
|
|
|
\\ (?>(?&PerlOWS)) |
1485
|
|
|
|
|
|
|
(? (?> my | our | state ) ) |
1486
|
|
|
|
|
|
|
| |
1487
|
|
|
|
|
|
|
(? (?> my | our | state ) ) |
1488
|
|
|
|
|
|
|
(?>(?&PerlOWS)) \\ |
1489
|
|
|
|
|
|
|
) |
1490
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
1491
|
|
|
|
|
|
|
(? |
1492
|
|
|
|
|
|
|
(?> (?&PerlVariableScalar) |
1493
|
|
|
|
|
|
|
| (?&PerlVariableArray) |
1494
|
|
|
|
|
|
|
| (?&PerlVariableHash) |
1495
|
|
|
|
|
|
|
) |
1496
|
|
|
|
|
|
|
) |
1497
|
|
|
|
|
|
|
| |
1498
|
|
|
|
|
|
|
# Implicitly aliased iterator variable... |
1499
|
|
|
|
|
|
|
(?> (? my | our | state ) (?>(?&PerlOWS)) )?+ |
1500
|
|
|
|
|
|
|
(? (?&PerlVariableScalar) ) |
1501
|
|
|
|
|
|
|
)?+ |
1502
|
|
|
|
|
|
|
(?= [^\n]* |
1503
|
|
|
|
|
|
|
(?
|
1504
|
|
|
|
|
|
|
(?
|
1505
|
|
|
|
|
|
|
\h* \# \h* |
1506
|
|
|
|
|
|
|
(? [^\n]* ) |
1507
|
|
|
|
|
|
|
| |
1508
|
|
|
|
|
|
|
(?) |
1509
|
|
|
|
|
|
|
) |
1510
|
|
|
|
|
|
|
(?&_record_and_disallow_decls) |
1511
|
|
|
|
|
|
|
|
1512
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
1513
|
|
|
|
|
|
|
(?: (?> (?&PerlParenthesesList) | (?&PerlQuotelikeQW) ) ) |
1514
|
|
|
|
|
|
|
) |
1515
|
|
|
|
|
|
|
| |
1516
|
|
|
|
|
|
|
(?> while | until) \b (?>(?&PerlOWS)) |
1517
|
|
|
|
|
|
|
(?&_allow_decls) |
1518
|
|
|
|
|
|
|
(?&PerlParenthesesList) |
1519
|
|
|
|
|
|
|
(?= [^\n]* |
1520
|
|
|
|
|
|
|
(?
|
1521
|
|
|
|
|
|
|
(?
|
1522
|
|
|
|
|
|
|
\h* \# \h* |
1523
|
|
|
|
|
|
|
(? [^\n]* ) |
1524
|
|
|
|
|
|
|
| |
1525
|
|
|
|
|
|
|
(?) |
1526
|
|
|
|
|
|
|
) |
1527
|
|
|
|
|
|
|
(?&_record_and_disallow_decls) |
1528
|
|
|
|
|
|
|
) |
1529
|
|
|
|
|
|
|
|
1530
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
1531
|
|
|
|
|
|
|
(?&_install_pending_decls) |
1532
|
|
|
|
|
|
|
(?>(?&PerlBlock)) |
1533
|
|
|
|
|
|
|
|
1534
|
|
|
|
|
|
|
(?: |
1535
|
|
|
|
|
|
|
(?>(?&PerlOWS)) continue |
1536
|
|
|
|
|
|
|
(?>(?&PerlOWS)) (?&PerlBlock) |
1537
|
|
|
|
|
|
|
)?+ |
1538
|
|
|
|
|
|
|
(?&_pop_scope) |
1539
|
|
|
|
|
|
|
| |
1540
|
|
|
|
|
|
|
(?> given | when ) \b (?>(?&PerlOWS)) |
1541
|
|
|
|
|
|
|
(?>(?&PerlParenthesesList)) (?>(?&PerlOWS)) |
1542
|
|
|
|
|
|
|
(?&_install_pending_decls) |
1543
|
|
|
|
|
|
|
(?&PerlBlock) |
1544
|
|
|
|
|
|
|
(?&_pop_scope) |
1545
|
|
|
|
|
|
|
| |
1546
|
|
|
|
|
|
|
(?&PerlStdControlBlock) |
1547
|
|
|
|
|
|
|
(?&_pop_scope) |
1548
|
|
|
|
|
|
|
| |
1549
|
|
|
|
|
|
|
(?&_revert_scope_on_failure) |
1550
|
|
|
|
|
|
|
) |
1551
|
|
|
|
|
|
|
) |
1552
|
|
|
|
|
|
|
|
1553
|
|
|
|
|
|
|
(? |
1554
|
|
|
|
|
|
|
(?&_push_scope) |
1555
|
|
|
|
|
|
|
(?> |
1556
|
|
|
|
|
|
|
(?> (?> my | state | our ) \b (?>(?&PerlOWS)) )?+ |
1557
|
|
|
|
|
|
|
(? sub \b ) (?>(?&PerlOWS)) |
1558
|
|
|
|
|
|
|
(?>(?&PerlOldQualifiedIdentifier)) (?&PerlOWS) |
1559
|
|
|
|
|
|
|
| |
1560
|
|
|
|
|
|
|
AUTOLOAD (?&PerlOWS) |
1561
|
|
|
|
|
|
|
| |
1562
|
|
|
|
|
|
|
DESTROY (?&PerlOWS) |
1563
|
|
|
|
|
|
|
) |
1564
|
|
|
|
|
|
|
|
1565
|
|
|
|
|
|
|
(?&_allow_decls) |
1566
|
|
|
|
|
|
|
(?> |
1567
|
|
|
|
|
|
|
# Perl pre 5.028 |
1568
|
|
|
|
|
|
|
(?: |
1569
|
|
|
|
|
|
|
(?> |
1570
|
|
|
|
|
|
|
(?&PerlParenthesesList) # Parameter list |
1571
|
|
|
|
|
|
|
| |
1572
|
|
|
|
|
|
|
\( [^)]*+ \) # Prototype ( |
1573
|
|
|
|
|
|
|
) |
1574
|
|
|
|
|
|
|
(?&PerlOWS) |
1575
|
|
|
|
|
|
|
)?+ |
1576
|
|
|
|
|
|
|
(?: (?>(?&PerlAttributes)) (?&PerlOWS) )?+ |
1577
|
|
|
|
|
|
|
(?&_record_and_disallow_decls) |
1578
|
|
|
|
|
|
|
| |
1579
|
|
|
|
|
|
|
# Perl post 5.028 |
1580
|
|
|
|
|
|
|
(?: (?>(?&PerlAttributes)) (?&PerlOWS) )?+ |
1581
|
|
|
|
|
|
|
(?: (?>(?&PerlParenthesesList)) (?&PerlOWS) )?+ # Parameter list |
1582
|
|
|
|
|
|
|
(?&_record_and_disallow_decls) |
1583
|
|
|
|
|
|
|
)?+ |
1584
|
|
|
|
|
|
|
(?&_install_pending_decls) |
1585
|
|
|
|
|
|
|
(?> ; | (?&PerlBlock)) |
1586
|
|
|
|
|
|
|
(?&_pop_scope) |
1587
|
|
|
|
|
|
|
| |
1588
|
|
|
|
|
|
|
(?&_revert_scope_on_failure) |
1589
|
|
|
|
|
|
|
) |
1590
|
|
|
|
|
|
|
|
1591
|
|
|
|
|
|
|
(? |
1592
|
|
|
|
|
|
|
(?&_push_scope) |
1593
|
|
|
|
|
|
|
(? sub \b ) |
1594
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
1595
|
|
|
|
|
|
|
|
1596
|
|
|
|
|
|
|
(?&_allow_decls) |
1597
|
|
|
|
|
|
|
(?: |
1598
|
|
|
|
|
|
|
# Perl pre 5.028 |
1599
|
|
|
|
|
|
|
(?: |
1600
|
|
|
|
|
|
|
(?> |
1601
|
|
|
|
|
|
|
(?&PerlParenthesesList) # Parameter list |
1602
|
|
|
|
|
|
|
| |
1603
|
|
|
|
|
|
|
\( [^)]*+ \) # Prototype ( |
1604
|
|
|
|
|
|
|
) |
1605
|
|
|
|
|
|
|
(?&PerlOWS) |
1606
|
|
|
|
|
|
|
)?+ |
1607
|
|
|
|
|
|
|
(?: (?>(?&PerlAttributes)) (?&PerlOWS) )?+ |
1608
|
|
|
|
|
|
|
(?= [^\n]* |
1609
|
|
|
|
|
|
|
(?
|
1610
|
|
|
|
|
|
|
(?
|
1611
|
|
|
|
|
|
|
\h* \# \h* |
1612
|
|
|
|
|
|
|
(? [^\n]* ) |
1613
|
|
|
|
|
|
|
| |
1614
|
|
|
|
|
|
|
(?) |
1615
|
|
|
|
|
|
|
) |
1616
|
|
|
|
|
|
|
(?&_record_and_disallow_decls) |
1617
|
|
|
|
|
|
|
| |
1618
|
|
|
|
|
|
|
# Perl post 5.028 |
1619
|
|
|
|
|
|
|
(?: (?>(?&PerlAttributes)) (?&PerlOWS) )?+ |
1620
|
|
|
|
|
|
|
(?: (?&PerlParenthesesList) (?&PerlOWS) )?+ # Parameter list |
1621
|
|
|
|
|
|
|
(?= [^\n]* |
1622
|
|
|
|
|
|
|
(?
|
1623
|
|
|
|
|
|
|
(?
|
1624
|
|
|
|
|
|
|
\h* \# \h* |
1625
|
|
|
|
|
|
|
(? [^\n]* ) |
1626
|
|
|
|
|
|
|
| |
1627
|
|
|
|
|
|
|
(?) |
1628
|
|
|
|
|
|
|
) |
1629
|
|
|
|
|
|
|
(?&_record_and_disallow_decls) |
1630
|
|
|
|
|
|
|
)?+ |
1631
|
|
|
|
|
|
|
(?&_install_pending_decls) |
1632
|
|
|
|
|
|
|
(?&PerlBlock) |
1633
|
|
|
|
|
|
|
(?&_pop_scope) |
1634
|
|
|
|
|
|
|
| |
1635
|
|
|
|
|
|
|
(?&_revert_scope_on_failure) |
1636
|
|
|
|
|
|
|
) |
1637
|
|
|
|
|
|
|
|
1638
|
|
|
|
|
|
|
(? |
1639
|
|
|
|
|
|
|
(?> (? my | state | our ) ) \b (?>(?&PerlOWS)) |
1640
|
|
|
|
|
|
|
(?: (?&PerlQualifiedIdentifier) (?&PerlOWS) )?+ |
1641
|
|
|
|
|
|
|
(?&_allow_decls) |
1642
|
|
|
|
|
|
|
(?: |
1643
|
|
|
|
|
|
|
(?&PerlLvalue) |
1644
|
|
|
|
|
|
|
(?= [^\n]* |
1645
|
|
|
|
|
|
|
(?
|
1646
|
|
|
|
|
|
|
(?
|
1647
|
|
|
|
|
|
|
\h* \# \h* |
1648
|
|
|
|
|
|
|
(? [^\n]* ) |
1649
|
|
|
|
|
|
|
| |
1650
|
|
|
|
|
|
|
(?) |
1651
|
|
|
|
|
|
|
) |
1652
|
|
|
|
|
|
|
(?&_record_and_disallow_decls) |
1653
|
|
|
|
|
|
|
| |
1654
|
|
|
|
|
|
|
(?&_record_and_disallow_decls) |
1655
|
|
|
|
|
|
|
(?!) |
1656
|
|
|
|
|
|
|
) |
1657
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
1658
|
|
|
|
|
|
|
(?&PerlAttributes)?+ |
1659
|
|
|
|
|
|
|
) |
1660
|
|
|
|
|
|
|
|
1661
|
|
|
|
|
|
|
(? |
1662
|
|
|
|
|
|
|
(?> |
1663
|
|
|
|
|
|
|
\\?+ |
1664
|
|
|
|
|
|
|
(?: |
1665
|
|
|
|
|
|
|
(? (?> \$\#? | [@%] ) (?>(?&PerlOWS)) (?&PerlIdentifier) ) |
1666
|
|
|
|
|
|
|
(?&_save_var_after_ows) |
1667
|
|
|
|
|
|
|
) |
1668
|
|
|
|
|
|
|
| |
1669
|
|
|
|
|
|
|
\( |
1670
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
1671
|
|
|
|
|
|
|
(?> \\?+ |
1672
|
|
|
|
|
|
|
(? (?> \$\#? | [@%] ) (?>(?&PerlOWS)) (?&PerlIdentifier) ) |
1673
|
|
|
|
|
|
|
(?&_save_var_after_ows) |
1674
|
|
|
|
|
|
|
| |
1675
|
|
|
|
|
|
|
undef |
1676
|
|
|
|
|
|
|
) |
1677
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
1678
|
|
|
|
|
|
|
(?: |
1679
|
|
|
|
|
|
|
(?>(?&PerlComma)) |
1680
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
1681
|
|
|
|
|
|
|
(?> \\?+ |
1682
|
|
|
|
|
|
|
(? (?> \$\#? | [@%] ) (?>(?&PerlOWS)) (?&PerlIdentifier) ) |
1683
|
|
|
|
|
|
|
(?&_save_var_after_ows) |
1684
|
|
|
|
|
|
|
| |
1685
|
|
|
|
|
|
|
undef |
1686
|
|
|
|
|
|
|
) |
1687
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
1688
|
|
|
|
|
|
|
)*+ |
1689
|
|
|
|
|
|
|
(?: (?>(?&PerlComma)) (?&PerlOWS) )?+ |
1690
|
|
|
|
|
|
|
\) |
1691
|
|
|
|
|
|
|
) |
1692
|
|
|
|
|
|
|
) |
1693
|
|
|
|
|
|
|
|
1694
|
|
|
|
|
|
|
(? |
1695
|
|
|
|
|
|
|
(?> (? my | state | our ) ) \b (?>(?&PerlOWS)) |
1696
|
|
|
|
|
|
|
(?: (?&PerlQualifiedIdentifier) (?&PerlOWS) )?+ |
1697
|
|
|
|
|
|
|
(?&_allow_decls) |
1698
|
|
|
|
|
|
|
(?: |
1699
|
|
|
|
|
|
|
(?&PerlLvalue) |
1700
|
|
|
|
|
|
|
(?= [^\n]* |
1701
|
|
|
|
|
|
|
(?
|
1702
|
|
|
|
|
|
|
(?
|
1703
|
|
|
|
|
|
|
\h* \# \h* |
1704
|
|
|
|
|
|
|
(? [^\n]* ) |
1705
|
|
|
|
|
|
|
| |
1706
|
|
|
|
|
|
|
(?) |
1707
|
|
|
|
|
|
|
) |
1708
|
|
|
|
|
|
|
(?&_record_and_disallow_decls) |
1709
|
|
|
|
|
|
|
| |
1710
|
|
|
|
|
|
|
(?&_disallow_decls) |
1711
|
|
|
|
|
|
|
(?!) |
1712
|
|
|
|
|
|
|
) |
1713
|
|
|
|
|
|
|
(?>(?&PerlOWS)) |
1714
|
|
|
|
|
|
|
(?&PerlAttributes)?+ |
1715
|
|
|
|
|
|
|
| |
1716
|
|
|
|
|
|
|
(?&PerlStdTerm) |
1717
|
|
|
|
|
|
|
) |
1718
|
|
|
|
|
|
|
|
1719
|
|
|
|
|
|
|
(? (? (?&PerlStdVariableScalar) ) (?&_save_var_after_ows) ) |
1720
|
|
|
|
|
|
|
(? (? (?&PerlStdVariableArray) ) (?&_save_var_after_ows) ) |
1721
|
|
|
|
|
|
|
(? (? (?&PerlStdVariableHash) ) (?&_save_var_after_ows) ) |
1722
|
|
|
|
|
|
|
|
1723
|
|
|
|
|
|
|
(? |
1724
|
|
|
|
|
|
|
(? (?&PerlStdVariableScalarNoSpace) ) (?&_save_var_no_ows) |
1725
|
|
|
|
|
|
|
) |
1726
|
|
|
|
|
|
|
(? |
1727
|
|
|
|
|
|
|
(? (?&PerlStdVariableArrayNoSpace) ) (?&_save_var_no_ows) |
1728
|
|
|
|
|
|
|
) |
1729
|
|
|
|
|
|
|
|
1730
|
|
|
|
|
|
|
(? |
1731
|
|
|
|
|
|
|
" [^"\$\@\\]*+ |
1732
|
|
|
|
|
|
|
(?: (?> \\. | (?&PerlScalarAccessNoSpace) | (?&PerlArrayAccessNoSpace) ) |
1733
|
|
|
|
|
|
|
[^"\$\@\\]*+ |
1734
|
|
|
|
|
|
|
)*+ |
1735
|
|
|
|
|
|
|
" |
1736
|
|
|
|
|
|
|
| |
1737
|
2514
|
|
|
|
|
7401
|
(?&PerlStdString) |
|
25140
|
|
|
|
|
33151
|
|
|
2514
|
|
|
|
|
17121
|
|
|
2514
|
|
|
|
|
49808
|
|
1738
|
|
|
|
|
|
|
) |
1739
|
|
|
|
|
|
|
|
1740
|
|
|
|
|
|
|
# Test and record instances of any variable encountered... |
1741
|
|
|
|
|
|
|
(?<_save_var_after_ows> |
1742
|
|
|
|
|
|
|
(?{ my $var = (grep {defined} @{$-{var}})[-1]; [$var, pos() - length($var) ] }) |
1743
|
126
|
|
|
|
|
287
|
(?= (?>(?&PerlOWS)) (?> (? \[ ) | (? \{ ) | ) ) |
|
1260
|
|
|
|
|
1667
|
|
|
126
|
|
|
|
|
839
|
|
|
126
|
|
|
|
|
1105
|
|
1744
|
|
|
|
|
|
|
(?&_save_var) |
1745
|
|
|
|
|
|
|
) |
1746
|
|
|
|
|
|
|
|
1747
|
|
|
|
|
|
|
(?<_save_var_no_ows> |
1748
|
|
|
|
|
|
|
(?{ my $var = (grep {defined} @{$-{var}})[-1]; [$var, pos() - length($var) ] }) |
1749
|
|
|
|
|
|
|
(?= (? \[ ) | (? \{ ) | ) |
1750
|
2640
|
|
|
|
|
8260
|
(?&_save_var) |
|
2640
|
|
|
|
|
4801
|
|
1751
|
2640
|
100
|
|
|
|
4934
|
) |
1752
|
2554
|
|
|
|
|
2987
|
|
1753
|
2554
|
50
|
|
|
|
5247
|
(?<_save_var> |
1754
|
0
|
|
|
|
|
0
|
(?{ |
1755
|
0
|
|
|
|
|
0
|
my ($var, $varid) = @{$^R}; |
1756
|
|
|
|
|
|
|
if (length($var) > 2) { |
1757
|
|
|
|
|
|
|
while (1) { |
1758
|
|
|
|
|
|
|
last if substr($var,1,1) ne '$'; |
1759
|
|
|
|
|
|
|
substr($var, 0, 1, q{}); |
1760
|
2640
|
100
|
|
|
|
4808
|
$varid++; |
1761
|
949
|
|
|
|
|
988
|
} |
|
949
|
|
|
|
|
64988
|
|
1762
|
|
|
|
|
|
|
} |
1763
|
|
|
|
|
|
|
|
1764
|
|
|
|
|
|
|
# Update the scope's information if this variable is being declared... |
1765
|
|
|
|
|
|
|
if ($Code::ART::varscope[-1]{allow_decls}) { |
1766
|
|
|
|
|
|
|
push @{$Code::ART::varscope[-1]{decls}}, |
1767
|
1691
|
|
|
|
|
1860
|
{ id => $varid, decl_name => $var, raw_name => substr($var,1) }; |
1768
|
1691
|
|
|
|
|
2699
|
} |
1769
|
1691
|
100
|
66
|
|
|
5479
|
|
1770
|
|
|
|
|
|
|
# Otherwise record its usage in the appropriate slot (if any)... |
1771
|
|
|
|
|
|
|
else { |
1772
|
1691
|
|
|
|
|
4197
|
my $varlen = length($var); |
1773
|
1691
|
50
|
|
|
|
3468
|
my $sigil = substr($var, 0, 1, q{}); |
1774
|
|
|
|
|
|
|
my $twigil = $varlen > 1 && substr($var, 0, 1) eq '#' |
1775
|
1691
|
100
|
100
|
|
|
11194
|
? substr($var, 0, 1, q{}) |
|
|
100
|
|
|
|
|
|
1776
|
|
|
|
|
|
|
: q{}; |
1777
|
|
|
|
|
|
|
(my $cleanvar = $var) =~ s/[^\w:'^]+//g; |
1778
|
|
|
|
|
|
|
$var = $cleanvar if length($cleanvar) > 0; |
1779
|
1691
|
|
66
|
|
|
337753
|
$var = ( $+{array} || $twigil ? '@' |
1780
|
|
|
|
|
|
|
: $+{hash} ? '%' |
1781
|
|
|
|
|
|
|
: $sigil) . $var; |
1782
|
|
|
|
|
|
|
$Code::ART::varuse |
1783
|
|
|
|
|
|
|
{$Code::ART::varscope[-1]{ids}{$var} // $var} |
1784
|
|
|
|
|
|
|
{$varid} = $varlen; |
1785
|
|
|
|
|
|
|
} |
1786
|
|
|
|
|
|
|
}) |
1787
|
10491
|
|
|
|
|
207086
|
) |
|
10491
|
|
|
|
|
152916
|
|
1788
|
|
|
|
|
|
|
|
1789
|
|
|
|
|
|
|
# Set up a new nested scope replicating the surrounding scope... |
1790
|
|
|
|
|
|
|
(?<_push_scope> |
1791
|
|
|
|
|
|
|
(?{ push @Code::ART::varscope, { |
1792
|
|
|
|
|
|
|
ids => {%{$Code::ART::varscope[-1]{ids}}}, |
1793
|
|
|
|
|
|
|
decls => [], |
1794
|
|
|
|
|
|
|
}; |
1795
|
|
|
|
|
|
|
}) |
1796
|
758
|
|
|
|
|
6223
|
) |
1797
|
758
|
|
|
|
|
1017
|
|
1798
|
758
|
|
|
|
|
808
|
# Tear down a nested scope... |
|
758
|
|
|
|
|
1711
|
|
1799
|
|
|
|
|
|
|
(?<_pop_scope> |
1800
|
3157
|
|
|
|
|
29847
|
(?{ |
1801
|
|
|
|
|
|
|
$Code::ART::oldscope = pop @Code::ART::varscope; |
1802
|
|
|
|
|
|
|
$Code::ART::end_of_scope = pos(); |
1803
|
|
|
|
|
|
|
for my $id (values %{$Code::ART::oldscope->{ids}}) { |
1804
|
|
|
|
|
|
|
$Code::ART::varinfo{$id}{end_of_scope} |
1805
|
|
|
|
|
|
|
= $Code::ART::end_of_scope; |
1806
|
|
|
|
|
|
|
} |
1807
|
9733
|
|
|
|
|
510260
|
}) |
1808
|
|
|
|
|
|
|
) |
1809
|
|
|
|
|
|
|
|
1810
|
|
|
|
|
|
|
# Clean up a scope that's closing, but also propagate failure... |
1811
|
|
|
|
|
|
|
(?<_revert_scope_on_failure> |
1812
|
|
|
|
|
|
|
(?{ pop @Code::ART::varscope; }) |
1813
|
742
|
|
|
|
|
29105
|
(?!) |
1814
|
|
|
|
|
|
|
) |
1815
|
|
|
|
|
|
|
|
1816
|
|
|
|
|
|
|
# Allow/disallow variables to be recorded as declarations... |
1817
|
0
|
|
|
|
|
0
|
(?<_allow_decls> |
1818
|
|
|
|
|
|
|
(?{ $Code::ART::varscope[-1]{allow_decls} = 1; }) |
1819
|
|
|
|
|
|
|
) |
1820
|
|
|
|
|
|
|
|
1821
|
|
|
|
|
|
|
(?<_disallow_decls> |
1822
|
|
|
|
|
|
|
(?{ $Code::ART::varscope[-1]{allow_decls} = 0; }) |
1823
|
742
|
|
|
|
|
1174
|
) |
|
742
|
|
|
|
|
1529
|
|
1824
|
991
|
|
33
|
|
|
2115
|
|
1825
|
991
|
|
|
|
|
4556
|
# Disallow declarations but remember the ones that were already found... |
1826
|
7928
|
|
|
|
|
14036
|
(?<_record_and_disallow_decls> |
|
991
|
|
|
|
|
4850
|
|
1827
|
|
|
|
|
|
|
(?{ |
1828
|
|
|
|
|
|
|
for my $decl (@{$Code::ART::varscope[-1]{decls}}) { |
1829
|
|
|
|
|
|
|
my $decl_name = $decl->{decl_name} // $+{var}; |
1830
|
|
|
|
|
|
|
@{$decl}{'declarator', 'sigil', 'desc', 'decl_name', 'raw_name', 'aliases'} |
1831
|
991
|
|
50
|
|
|
1145
|
= ( (grep {defined} @{$-{declarator}})[-1] // q{}, |
|
|
|
100
|
|
|
|
|
1832
|
|
|
|
|
|
|
substr($_, $decl->{id}, 1), |
1833
|
|
|
|
|
|
|
$+{desc} // q{}, |
1834
|
742
|
|
|
|
|
74371
|
$decl_name, |
1835
|
|
|
|
|
|
|
$decl->{raw_name}, |
1836
|
|
|
|
|
|
|
[] |
1837
|
|
|
|
|
|
|
); |
1838
|
|
|
|
|
|
|
} |
1839
|
|
|
|
|
|
|
$Code::ART::varscope[-1]{allow_decls} = 0; |
1840
|
|
|
|
|
|
|
}) |
1841
|
|
|
|
|
|
|
) |
1842
|
1533
|
|
|
|
|
43165
|
|
|
1533
|
|
|
|
|
3439
|
|
1843
|
739
|
|
|
|
|
1807
|
# Make new variable declarations effective in the current scope... |
1844
|
739
|
|
|
|
|
3244
|
(?<_install_pending_decls> |
1845
|
|
|
|
|
|
|
(?: (?&PerlOWS) \{ )?+ |
1846
|
739
|
|
|
|
|
1037
|
(?{ |
|
739
|
|
|
|
|
1135
|
|
1847
|
|
|
|
|
|
|
for my $decl (@{$Code::ART::varscope[-1]{decls}}) { |
1848
|
739
|
|
33
|
|
|
1856
|
$Code::ART::varscope[-1]{ids}{$decl->{decl_name}} = $decl->{id}; |
1849
|
739
|
|
|
|
|
1333
|
@{$Code::ART::varinfo{$decl->{id}}} |
1850
|
739
|
|
|
|
|
1624
|
{'declarator', 'sigil', 'desc', 'decl_name', 'raw_name'} |
1851
|
|
|
|
|
|
|
= @{$decl}{'declarator', 'sigil', 'desc', 'decl_name', 'raw_name'}; |
1852
|
1533
|
|
|
|
|
37734
|
$Code::ART::varinfo{$decl->{id}}->{sigil} |
1853
|
|
|
|
|
|
|
//= substr($_, $decl->{id},1); |
1854
|
|
|
|
|
|
|
$Code::ART::varinfo{$decl->{id}}->{start_of_scope} = pos(); |
1855
|
|
|
|
|
|
|
$Code::ART::varuse{$decl->{id}} = {}; |
1856
|
|
|
|
|
|
|
} |
1857
|
|
|
|
|
|
|
$Code::ART::varscope[-1]{decls} = []; |
1858
|
|
|
|
|
|
|
}) |
1859
|
|
|
|
|
|
|
(?!) # Backtrack to unwind matching the trailing block delimiter |
1860
|
|
|
|
|
|
|
| |
1861
|
493
|
|
|
|
|
27071
|
(?=) # Then match anyway, but at the original position |
1862
|
|
|
|
|
|
|
) |
1863
|
|
|
|
|
|
|
|
1864
|
|
|
|
|
|
|
# Reset pending variable declarations in current scope... |
1865
|
|
|
|
|
|
|
(?<_clear_pending_declaration> |
1866
|
|
|
|
|
|
|
(?{ $Code::ART::varscope[-1]{decls} = []; }) |
1867
|
|
|
|
|
|
|
) |
1868
|
|
|
|
|
|
|
) |
1869
|
57
|
100
|
|
|
|
2549
|
|
1870
|
|
|
|
|
|
|
$PPR::X::GRAMMAR |
1871
|
|
|
|
|
|
|
}xmso; |
1872
|
|
|
|
|
|
|
|
1873
|
56
|
|
|
|
|
148
|
# Return a failure report if unable to process source code... |
1874
|
56
|
|
|
|
|
370
|
return { failed => 'invalid source code', context => $PPR::X::ERROR } |
1875
|
843
|
100
|
|
|
|
1790
|
if !$matched; |
1876
|
|
|
|
|
|
|
|
1877
|
|
|
|
|
|
|
# Install usages and declaration locations... |
1878
|
|
|
|
|
|
|
my $undecl_id = -1; |
1879
|
|
|
|
|
|
|
for my $id (keys %Code::ART::varuse) { |
1880
|
|
|
|
|
|
|
if ($id !~ /^\d+$/) { |
1881
|
|
|
|
|
|
|
$Code::ART::varinfo{$undecl_id--} |
1882
|
|
|
|
|
|
|
= { decl_name => $id, |
1883
|
104
|
|
50
|
|
|
1036
|
sigil => substr($id,0,1), |
1884
|
|
|
|
|
|
|
raw_name => substr($id,1), |
1885
|
|
|
|
|
|
|
declarator => "", |
1886
|
|
|
|
|
|
|
desc => "", |
1887
|
|
|
|
|
|
|
declared_at => -1, |
1888
|
|
|
|
|
|
|
used_at => $Code::ART::varuse{$id} // [], |
1889
|
739
|
|
|
|
|
1684
|
start_of_scope => -1, |
1890
|
739
|
|
50
|
|
|
1474
|
end_of_scope => length($source), |
1891
|
|
|
|
|
|
|
}; |
1892
|
739
|
|
50
|
|
|
1717
|
} |
|
|
|
33
|
|
|
|
|
1893
|
|
|
|
|
|
|
else { |
1894
|
|
|
|
|
|
|
$Code::ART::varinfo{$id}{declared_at} = $id; |
1895
|
|
|
|
|
|
|
$Code::ART::varinfo{$id}{used_at} = $Code::ART::varuse{$id} // []; |
1896
|
|
|
|
|
|
|
$Code::ART::varinfo{$id}{start_of_scope} //= -1, |
1897
|
56
|
|
|
|
|
141
|
$Code::ART::varinfo{$id}{end_of_scope} //= length($source); |
1898
|
56
|
|
|
|
|
250
|
} |
1899
|
843
|
|
|
|
|
1382
|
} |
1900
|
843
|
|
|
|
|
1109
|
|
1901
|
|
|
|
|
|
|
# Install standard descriptions and apply analyses... |
1902
|
|
|
|
|
|
|
my %var_at; |
1903
|
843
|
|
|
|
|
1021
|
for my $varid (keys %Code::ART::varinfo) { |
|
843
|
|
|
|
|
2491
|
|
1904
|
1486
|
|
|
|
|
2673
|
my $var = $Code::ART::varinfo{$varid}; |
1905
|
11612
|
|
|
|
|
22058
|
my $var_name = $var->{raw_name}; |
1906
|
|
|
|
|
|
|
|
1907
|
|
|
|
|
|
|
# Invert usages... |
1908
|
|
|
|
|
|
|
for my $startpos (keys %{$var->{used_at}}) { |
1909
|
|
|
|
|
|
|
for my $offset (0 .. $var->{used_at}{$startpos}) { |
1910
|
843
|
|
|
|
|
1363
|
$var_at{ $startpos + $offset } = $varid; |
1911
|
843
|
100
|
|
|
|
2169
|
} |
1912
|
43
|
|
|
|
|
98
|
} |
|
43
|
|
|
|
|
110
|
|
|
43
|
|
|
|
|
107
|
|
1913
|
43
|
|
|
|
|
91
|
|
1914
|
|
|
|
|
|
|
# Check whether variable is a built-in... |
1915
|
|
|
|
|
|
|
$var->{is_builtin} = 0; |
1916
|
|
|
|
|
|
|
if (my $std_desc = $STD_VAR_DESC{$var->{decl_name}}) { |
1917
|
843
|
100
|
|
|
|
8001
|
@{$var}{'desc', 'aliases'} = @{$std_desc}{'desc', 'aliases'}; |
1918
|
|
|
|
|
|
|
$var->{is_builtin} = 1; |
1919
|
|
|
|
|
|
|
} |
1920
|
843
|
|
|
|
|
1638
|
|
1921
|
843
|
|
|
|
|
1637
|
# Check whether its name is unhelpful... |
1922
|
843
|
|
|
|
|
1304
|
$var->{is_cacogram} = $var_name =~ /\A$CACOGRAMS_PAT\Z/ ? 1 : 0; |
1923
|
843
|
|
|
|
|
2222
|
|
1924
|
15323
|
100
|
100
|
|
|
31415
|
# Check for homograms and parograms... |
1925
|
|
|
|
|
|
|
my $parograms_pat = _parograms_of($var_name); |
1926
|
9020
|
|
|
|
|
13632
|
$var->{homograms} = {}; |
1927
|
9020
|
100
|
|
|
|
14819
|
$var->{parograms} = {}; |
1928
|
|
|
|
|
|
|
for my $other_var (values %Code::ART::varinfo) { |
1929
|
9020
|
100
|
|
|
|
110464
|
next if $var == $other_var || !_share_scope($var, $other_var); |
1930
|
|
|
|
|
|
|
|
1931
|
3366
|
|
100
|
|
|
8646
|
my $other_name = $other_var->{raw_name}; |
1932
|
|
|
|
|
|
|
my ($gram_type, $matcher) = $other_name eq $var_name ? ('homograms', $var_name) |
1933
|
3366
|
|
|
|
|
7958
|
: ('parograms', $parograms_pat); |
1934
|
|
|
|
|
|
|
if ($other_name =~ /\A$matcher\z/) { |
1935
|
3366
|
|
|
|
|
7700
|
$var->{$gram_type}{$other_name} |
1936
|
|
|
|
|
|
|
//= { from=>$var->{declared_at}, to=>$var->{end_of_scope} }; |
1937
|
|
|
|
|
|
|
$var->{$gram_type}{$other_name}{from} |
1938
|
|
|
|
|
|
|
= min $var->{$gram_type}{$other_name}{from}, $other_var->{declared_at}; |
1939
|
|
|
|
|
|
|
$var->{$gram_type}{$other_name}{to} |
1940
|
|
|
|
|
|
|
= max $var->{$gram_type}{$other_name}{to}, $other_var->{end_of_scope}; |
1941
|
843
|
|
50
|
|
|
3489
|
} |
1942
|
|
|
|
|
|
|
} |
1943
|
|
|
|
|
|
|
|
1944
|
|
|
|
|
|
|
# Measure its scope... |
1945
|
|
|
|
|
|
|
$var->{scope_scale} |
1946
|
56
|
|
|
|
|
744
|
= ($var->{end_of_scope} - ($var->{declared_at} // 0)) / length($source); |
1947
|
|
|
|
|
|
|
} |
1948
|
|
|
|
|
|
|
|
1949
|
|
|
|
|
|
|
# Return all the information acquired... |
1950
|
|
|
|
|
|
|
return { |
1951
|
|
|
|
|
|
|
vars => \%Code::ART::varinfo, |
1952
|
|
|
|
|
|
|
var_at => \%var_at, |
1953
|
|
|
|
|
|
|
use_version => $Code::ART::use_version, |
1954
|
|
|
|
|
|
|
} |
1955
|
|
|
|
|
|
|
} |
1956
|
|
|
|
|
|
|
|
1957
|
|
|
|
|
|
|
|
1958
|
|
|
|
|
|
|
1; # Magic true value required at end of module |
1959
|
|
|
|
|
|
|
__END__ |