| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#!perl |
|
2
|
|
|
|
|
|
|
package Config::Perl; |
|
3
|
5
|
|
|
5
|
|
109932
|
use warnings; |
|
|
5
|
|
|
|
|
9
|
|
|
|
5
|
|
|
|
|
157
|
|
|
4
|
5
|
|
|
5
|
|
20
|
use strict; |
|
|
5
|
|
|
|
|
6
|
|
|
|
5
|
|
|
|
|
367
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = '0.02'; |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 Name |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
Config::Perl - Perl extension to parse configuration files written in a subset of Perl |
|
11
|
|
|
|
|
|
|
and (limited) undumping of data structures (safer than eval thanks to parsing via PPI) |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 Synopsis |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=for comment |
|
16
|
|
|
|
|
|
|
Remember to test this by copy/pasting to/from 91_author_pod.t |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use Config::Perl; |
|
19
|
|
|
|
|
|
|
my $parser = Config::Perl->new; |
|
20
|
|
|
|
|
|
|
my $data = $parser->parse_or_die( \<<' END_CONFIG_FILE' ); |
|
21
|
|
|
|
|
|
|
# This is the example configuration file |
|
22
|
|
|
|
|
|
|
$foo = "bar"; |
|
23
|
|
|
|
|
|
|
%text = ( test => ["Hello", "World!"] ); |
|
24
|
|
|
|
|
|
|
@vals = qw/ x y a /; |
|
25
|
|
|
|
|
|
|
END_CONFIG_FILE |
|
26
|
|
|
|
|
|
|
print $data->{'$foo'}, "\n"; # prints "bar\n" |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# Resulting $data: { |
|
29
|
|
|
|
|
|
|
# '$foo' => "bar", |
|
30
|
|
|
|
|
|
|
# '%text' => { test => ["Hello", "World!"] }, |
|
31
|
|
|
|
|
|
|
# '@vals' => ["x", "y", "a"], |
|
32
|
|
|
|
|
|
|
# }; |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=head1 Description |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
The goal of this module is to support the parsing of a small subset of Perl, |
|
37
|
|
|
|
|
|
|
primarily in order to parse configuration files written in that subset of Perl. |
|
38
|
|
|
|
|
|
|
As a side effect, this module can "undump" some data structures written by |
|
39
|
|
|
|
|
|
|
L and L - see L. |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
The code is parsed via L, eliminating the need for Perl's C. |
|
42
|
|
|
|
|
|
|
This should provide a higher level of safety* compared to C |
|
43
|
|
|
|
|
|
|
(even when making use of a module like L). |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
* B A "higher level of safety" does not mean "perfect safety". |
|
46
|
|
|
|
|
|
|
This software is distributed B; without even the implied |
|
47
|
|
|
|
|
|
|
warranty of B or B. |
|
48
|
|
|
|
|
|
|
See also the licence for this software. |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
This module attempts to provide 100% compatibility with Perl over the subset of Perl it supports. |
|
51
|
|
|
|
|
|
|
When a Perl feature is not supported by this module, it should complain |
|
52
|
|
|
|
|
|
|
that the feature is not supported, instead of silently giving a wrong result. |
|
53
|
|
|
|
|
|
|
If the output of a parse is different from how Perl would evaluate the same string, |
|
54
|
|
|
|
|
|
|
then that is a bug in this module that should be fixed by correcting the output |
|
55
|
|
|
|
|
|
|
or adding an error message that the particular feature is unsupported. |
|
56
|
|
|
|
|
|
|
However, the result of using this module to parse something that is not valid Perl is undefined; |
|
57
|
|
|
|
|
|
|
it may cause an error, or may fail in some other silent way. |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
This document describes version 0.02 of the module. |
|
60
|
|
|
|
|
|
|
Although this module is well-tested and working, it still lacks some |
|
61
|
|
|
|
|
|
|
features to make it I useful (see list below). |
|
62
|
|
|
|
|
|
|
Contributions are welcome! |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=head2 Interface |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
This module has a simple OO interface. A new parser is created |
|
67
|
|
|
|
|
|
|
with C<< Config::Perl->new >>, which currently does not take any arguments, |
|
68
|
|
|
|
|
|
|
and documents are parsed with either the method C or C. |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
my $parser = Config::Perl->new; |
|
71
|
|
|
|
|
|
|
my $out1 = $parser->parse_or_undef(\' $foo = "bar"; '); |
|
72
|
|
|
|
|
|
|
warn "parse failed: ".$parser->errstr unless defined $out1; |
|
73
|
|
|
|
|
|
|
my $out2 = $parser->parse_or_die('filename.pl'); |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
The arguments and return values of these two methods are (almost) the same: |
|
76
|
|
|
|
|
|
|
They each take exactly one argument, which is either a filename, |
|
77
|
|
|
|
|
|
|
or a reference to a string containing the code to be parsed |
|
78
|
|
|
|
|
|
|
(this is the same as L's C method). |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
The methods differ in that, as the names imply, C |
|
81
|
|
|
|
|
|
|
will C on errors, while C will return C; |
|
82
|
|
|
|
|
|
|
the error message is then accessible via the C method. |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
For a successful parse, the return value of each function is a hashref |
|
85
|
|
|
|
|
|
|
representing the "symbol table" of the parsed document. |
|
86
|
|
|
|
|
|
|
This "symbol table" hash is similar to, but not the same as, Perl's symbol table. |
|
87
|
|
|
|
|
|
|
The hash includes a key for every variable declared or assigned to in the document, |
|
88
|
|
|
|
|
|
|
the key is the name of the variable including its sigil. |
|
89
|
|
|
|
|
|
|
If the document ends with a plain value or list that is not part of an assignment, |
|
90
|
|
|
|
|
|
|
that value is saved in the "symbol table" hash with the key "C<_>" (a single underscore). |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
For example, the string C<"$foo=123; $bar=456;"> will return the data structure |
|
93
|
|
|
|
|
|
|
C<< { '$foo'=>123, '$bar'=>456 } >>, and the string C<"('foo','bar')"> will return the data |
|
94
|
|
|
|
|
|
|
structure C<< { _=>["foo","bar"] } >>. |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
Note that documents are currently always parsed in list context. |
|
97
|
|
|
|
|
|
|
For example, this means that a document like "C<@foo = ("a","b","c"); @foo>" |
|
98
|
|
|
|
|
|
|
will return the array's elements (C<"a","b","c">) instead of the item count (C<3>). |
|
99
|
|
|
|
|
|
|
This also means that the special hash element "C<_>" will currently always be an arrayref. |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=head2 What is currently supported |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=over |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=item * |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
plain scalars, arrays, hashes, lists |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=item * |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
arrayrefs and hashrefs constructed via C<[]> and C<{}> resp. |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=item * |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
declarations - only C, also C on the outermost level (document) |
|
116
|
|
|
|
|
|
|
where it is treated exactly like C; |
|
117
|
|
|
|
|
|
|
not supported are lexical C inside blocks, C or C |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=item * |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
assignments (except the return value of assignments is not yet implemented) |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=item * |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
simple array and hash subscripts (e.g. C<$x[1]>, C<$x[$y]>, C<$x{z}>, C<$x{"$y"}>) |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=item * |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
very simple variable interpolations in strings (currently only C<"hello$world"> or C<"foo${bar}quz">) |
|
130
|
|
|
|
|
|
|
and some escape sequences (e.g. C<"\x00">) |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=item * |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
C blocks (contents limited to the supported features listed here) |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=back |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=head2 What is not supported (yet) |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
I hope to achieve a balance where this module is useful, without becoming too much of a re-implementation of Perl. |
|
141
|
|
|
|
|
|
|
I've labeled these items with "wishlist", "maybe", and "no", depending on whether I currently feel that |
|
142
|
|
|
|
|
|
|
I'd like to support this feature in a later version, I'd consider supporting this feature if the need arises, |
|
143
|
|
|
|
|
|
|
or I currently don't think the feature should be implemented. |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=over |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=item * |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
lexical variables (C) (wishlist) |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=item * |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
taking references via C<\> and dereferencing (C<@{...}>, C<%{...}>, etc.) (wishlist) |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=item * |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
return values of assignments (e.g. C<$foo = do { $bar = "quz" }>) (maybe) |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=item * |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
operators other than assignment (maybe; supporting a subset, like concatenation, is wishlist) |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=item * |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
conditionals, like for example a very simple C (maybe) |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=item * |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
any functions (mostly this is "no"; supporting a very small subset of functions, e.g. C, is "maybe") |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=item * |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
anything that can't be resolved via a static parse (including Cs, many regexps, etc.) (no) |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=item * |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
Note this list is not complete. |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=back |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=head1 Author, Copyright, and License |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
Copyright (c) 2015 Hauke Daempfling (haukex@zero-g.net). |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
|
186
|
|
|
|
|
|
|
it under the same terms as Perl 5 itself. |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
For more information see the L, |
|
189
|
|
|
|
|
|
|
which should have been distributed with your copy of Perl. |
|
190
|
|
|
|
|
|
|
Try the command "C" or see |
|
191
|
|
|
|
|
|
|
L. |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=cut |
|
194
|
|
|
|
|
|
|
|
|
195
|
5
|
|
|
5
|
|
22
|
use Carp; |
|
|
5
|
|
|
|
|
15
|
|
|
|
5
|
|
|
|
|
272
|
|
|
196
|
5
|
|
|
5
|
|
22
|
use warnings::register; |
|
|
5
|
|
|
|
|
6
|
|
|
|
5
|
|
|
|
|
614
|
|
|
197
|
5
|
|
|
5
|
|
2656
|
use PPI (); |
|
|
5
|
|
|
|
|
862132
|
|
|
|
5
|
|
|
|
|
136
|
|
|
198
|
5
|
|
|
5
|
|
2180
|
use PPI::Dumper (); |
|
|
5
|
|
|
|
|
4074
|
|
|
|
5
|
|
|
|
|
14015
|
|
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub new { |
|
201
|
140
|
|
|
140
|
0
|
135549
|
my $class = shift; |
|
202
|
140
|
100
|
|
|
|
603
|
croak "new currently takes no arguments" if @_; |
|
203
|
139
|
|
|
|
|
414
|
my $self = { |
|
204
|
|
|
|
|
|
|
errstr => undef, |
|
205
|
|
|
|
|
|
|
out => undef, |
|
206
|
|
|
|
|
|
|
ctx => undef, # Note: valid values for ctx currently "list", "scalar", "scalar-void" |
|
207
|
|
|
|
|
|
|
}; |
|
208
|
139
|
|
|
|
|
505
|
return bless $self, $class; |
|
209
|
|
|
|
|
|
|
} |
|
210
|
2
|
|
|
2
|
0
|
12
|
sub errstr { return shift->{errstr} } |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
#TODO: make _errmsg a little prettier? |
|
213
|
15
|
|
|
15
|
|
66
|
sub _dump { return PPI::Dumper->new(shift,whitespace=>0,comments=>0,locations=>0)->string } |
|
214
|
15
|
|
|
15
|
|
87
|
sub _errmsg { chomp(my $e=_dump(shift)); $e=~s/^/\t/mg; return "<<< $e >>>" } |
|
|
15
|
|
|
|
|
2798
|
|
|
|
15
|
|
|
|
|
1642
|
|
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub parse_or_undef { ## no critic (RequireArgUnpacking) |
|
217
|
87
|
|
|
87
|
0
|
1358
|
my $self = shift; |
|
218
|
87
|
|
|
|
|
104
|
my $out = eval { $self->parse_or_die(@_) }; |
|
|
87
|
|
|
|
|
169
|
|
|
219
|
87
|
|
100
|
|
|
536
|
my $errmsg = $@||"Unknown error"; |
|
220
|
87
|
100
|
|
|
|
163
|
$self->{errstr} = defined $out ? undef : $errmsg; |
|
221
|
87
|
|
|
|
|
193
|
return $out; |
|
222
|
|
|
|
|
|
|
} |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub parse_or_die { |
|
225
|
147
|
|
|
147
|
0
|
3197
|
my ($self,$input) = @_; |
|
226
|
|
|
|
|
|
|
# PPI::Documents are not "complete" if they don't have a final semicolon, so tack on on there if it's missing |
|
227
|
147
|
100
|
100
|
|
|
1143
|
$input = \"$$input;" if ref $input eq 'SCALAR' && $$input!~/;\s*$/; |
|
228
|
147
|
|
|
|
|
550
|
$self->{doc} = my $doc = PPI::Document->new($input); |
|
229
|
147
|
|
100
|
|
|
313301
|
my $errmsg = PPI::Document->errstr||"Unknown error"; |
|
230
|
147
|
100
|
|
|
|
1495
|
$doc or croak "Parse failed: $errmsg"; |
|
231
|
146
|
100
|
|
|
|
359
|
$doc->complete or croak "Document incomplete (missing final semicolon?)"; |
|
232
|
144
|
|
|
|
|
37187
|
$self->{ctx} = 'list'; |
|
233
|
144
|
|
|
|
|
219
|
$self->{out} = {}; |
|
234
|
144
|
|
|
|
|
341
|
my @rv = $self->_handle_block($doc, outer=>1); |
|
235
|
126
|
100
|
|
|
|
280
|
$self->{out}{_} = \@rv if @rv; |
|
236
|
126
|
|
|
|
|
319
|
return $self->{out}; |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub _handle_block { ## no critic (ProhibitExcessComplexity) |
|
240
|
151
|
|
|
151
|
|
359
|
my ($self,$block,%param) = @_; |
|
241
|
151
|
50
|
66
|
|
|
1104
|
confess "invalid \$block class" |
|
242
|
|
|
|
|
|
|
unless $block->isa('PPI::Structure::Block') || $block->isa('PPI::Document'); |
|
243
|
151
|
100
|
|
|
|
344
|
return unless $block->schildren; |
|
244
|
149
|
|
|
|
|
1847
|
my @rv; |
|
245
|
149
|
|
|
|
|
309
|
my $el = $block->schild(0); |
|
246
|
149
|
|
|
|
|
1485
|
ELEMENT: while ($el) { |
|
247
|
|
|
|
|
|
|
# uncoverable branch true |
|
248
|
295
|
50
|
|
|
|
3230
|
$el->isa('PPI::Statement') or croak "Unsupported element\n"._errmsg($el); |
|
249
|
295
|
|
|
|
|
568
|
my @sc = $el->schildren; |
|
250
|
|
|
|
|
|
|
# remove semicolons from statements |
|
251
|
295
|
100
|
66
|
|
|
4019
|
if ( @sc && $sc[-1]->isa('PPI::Token::Structure') && $sc[-1]->content eq ';' ) |
|
|
|
|
66
|
|
|
|
|
|
252
|
286
|
|
|
|
|
1522
|
{ pop(@sc)->delete } |
|
253
|
295
|
50
|
|
|
|
8753
|
next ELEMENT unless @sc; # empty statement? |
|
254
|
|
|
|
|
|
|
# last statement in block gets its context, otherwise void context |
|
255
|
295
|
100
|
|
|
|
1564
|
local $self->{ctx} = $el->snext_sibling ? 'scalar-void' : $self->{ctx}; |
|
256
|
295
|
|
|
|
|
4963
|
my $is_assign; # remove this once _handle_assign return values implemented |
|
257
|
|
|
|
|
|
|
# variable declaration |
|
258
|
295
|
100
|
33
|
|
|
614
|
if ($el->class eq 'PPI::Statement::Variable') { |
|
|
|
100
|
33
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
# note that Perl does not allow array or hash elements in declarations |
|
260
|
|
|
|
|
|
|
# so we don't have to worry about subscripts here |
|
261
|
65
|
100
|
100
|
|
|
287
|
croak "Unsupported declaration type \"".$el->type."\"" |
|
262
|
|
|
|
|
|
|
unless $el->type eq 'our' || $el->type eq 'my'; |
|
263
|
64
|
100
|
66
|
|
|
1947
|
croak "Lexical variables (\"my\") not supported" # I'd like to support "my" soon |
|
|
|
|
66
|
|
|
|
|
|
264
|
|
|
|
|
|
|
unless $el->type eq 'our' || ($el->type eq 'my' && $param{outer}); |
|
265
|
|
|
|
|
|
|
# Note: Don't use $el->symbols, as that omits undefs on LHS! |
|
266
|
63
|
|
|
|
|
1406
|
$self->_handle_assign($el,$sc[1],$sc[3]); |
|
267
|
60
|
|
|
|
|
79
|
$is_assign=1; |
|
268
|
|
|
|
|
|
|
} |
|
269
|
|
|
|
|
|
|
elsif ($el->class eq 'PPI::Statement') { |
|
270
|
|
|
|
|
|
|
# assignment, possibly with symbol+subscript on the RHS |
|
271
|
226
|
100
|
100
|
|
|
3071
|
if ( (@sc==3||@sc==4) && $sc[1]->isa('PPI::Token::Operator') && $sc[1]->content eq '=' ) { ## no critic (ProhibitCascadingIfElse) |
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
272
|
181
|
|
|
|
|
809
|
$self->_handle_assign($el,$sc[0],$sc[2]); |
|
273
|
181
|
|
|
|
|
203
|
$is_assign=1; |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
# assignment assumed to have a symbol+subscript on the LHS |
|
276
|
|
|
|
|
|
|
elsif ( (@sc==4||@sc==5) && $sc[2]->isa('PPI::Token::Operator') && $sc[2]->content eq '=' ) { |
|
277
|
6
|
|
|
|
|
33
|
$self->_handle_assign($el,$sc[0],$sc[3]); |
|
278
|
3
|
|
|
|
|
4
|
$is_assign=1; |
|
279
|
|
|
|
|
|
|
} |
|
280
|
|
|
|
|
|
|
# do-BLOCK |
|
281
|
|
|
|
|
|
|
elsif ( @sc==2 && $sc[0]->isa('PPI::Token::Word') && $sc[0]->literal eq 'do' |
|
282
|
|
|
|
|
|
|
&& $sc[1]->isa('PPI::Structure::Block') ) { |
|
283
|
5
|
|
|
|
|
98
|
my @tmprv = $self->_handle_block($sc[1]); |
|
284
|
4
|
100
|
|
|
|
21
|
@rv = @tmprv unless $self->{ctx} eq 'scalar-void'; |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
# single statements |
|
287
|
|
|
|
|
|
|
elsif ( @sc==1 || (@sc==2 && $sc[0]->isa('PPI::Token::Symbol') && $sc[1]->isa('PPI::Structure::Subscript')) ) { |
|
288
|
31
|
|
|
|
|
92
|
my @tmprv = $self->_handle_value($sc[0]); |
|
289
|
24
|
100
|
|
|
|
124
|
@rv = @tmprv unless $self->{ctx} eq 'scalar-void'; |
|
290
|
24
|
100
|
|
|
|
545
|
warnings::warnif("value in void context") if $self->{ctx} eq 'scalar-void'; |
|
291
|
|
|
|
|
|
|
} |
|
292
|
|
|
|
|
|
|
# push |
|
293
|
|
|
|
|
|
|
elsif ( @sc>2 && $sc[0]->isa('PPI::Token::Word') && $sc[0]->literal eq 'push') { |
|
294
|
1
|
|
|
|
|
42
|
croak "don't support push\n"._errmsg($el); # I'm considering supporting push |
|
295
|
|
|
|
|
|
|
} |
|
296
|
2
|
|
|
|
|
7
|
else { croak "Unsupported element\n"._errmsg($el) } |
|
297
|
|
|
|
|
|
|
} |
|
298
|
|
|
|
|
|
|
elsif ( $el->isa('PPI::Statement::Compound') && @sc==1 && $sc[0]->isa('PPI::Token::Label') ) { |
|
299
|
|
|
|
|
|
|
# ignore labels |
|
300
|
|
|
|
|
|
|
} |
|
301
|
0
|
|
|
|
|
0
|
else { croak "Unsupported element ".$el->class." in\n"._errmsg($el) } |
|
302
|
276
|
100
|
100
|
|
|
1325
|
if ($is_assign && $self->{ctx} ne 'scalar-void') { |
|
303
|
|
|
|
|
|
|
# special case: the last statement of the outermost block |
|
304
|
|
|
|
|
|
|
#TODO: Would it make sense to not error out on *any* assignment at the end of a block, not just the outermost one? |
|
305
|
104
|
50
|
33
|
|
|
335
|
if ($param{outer} && !$el->snext_sibling) |
|
306
|
|
|
|
|
|
|
{} # currently nothing; could warn here? |
|
307
|
|
|
|
|
|
|
else |
|
308
|
0
|
|
|
|
|
0
|
{ croak "Assignment return values not implemented (current context is $$self{ctx}) in\n"._errmsg($el) } |
|
309
|
|
|
|
|
|
|
} |
|
310
|
276
|
|
|
|
|
2071
|
} continue { $el = $el->snext_sibling } |
|
311
|
130
|
|
|
|
|
1800
|
return @rv; |
|
312
|
|
|
|
|
|
|
} |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
# returns nothing (yet) |
|
315
|
|
|
|
|
|
|
sub _handle_assign { |
|
316
|
250
|
|
|
250
|
|
306
|
my ($self,$as,$lhs,$rhs) = @_; |
|
317
|
250
|
50
|
66
|
|
|
410
|
confess "invalid \$as class" |
|
318
|
|
|
|
|
|
|
unless $as->class eq 'PPI::Statement' || $as->class eq 'PPI::Statement::Variable'; |
|
319
|
|
|
|
|
|
|
# Note we expect our caller to pick the correct $lhs and $rhs children from $as, |
|
320
|
|
|
|
|
|
|
# and at the moment *some* call sites also already check the number of children. |
|
321
|
|
|
|
|
|
|
# Possible To-Do for Later: Clean up the _handle_assign calling |
|
322
|
250
|
100
|
66
|
|
|
1249
|
croak "bad assignment statement length in:\n"._errmsg($as) |
|
323
|
|
|
|
|
|
|
if $as->schildren<3 || $as->schildren>5; |
|
324
|
|
|
|
|
|
|
|
|
325
|
249
|
|
|
|
|
5711
|
my $lhs_scalar; |
|
326
|
|
|
|
|
|
|
my @lhs; |
|
327
|
249
|
100
|
|
|
|
569
|
if ($lhs->isa('PPI::Token::Symbol')) { |
|
|
|
50
|
|
|
|
|
|
|
328
|
240
|
|
|
|
|
423
|
@lhs = ($self->_handle_symbol($lhs)); |
|
329
|
237
|
|
|
|
|
401
|
$lhs_scalar = $lhs[0]->{atype} eq '$'; |
|
330
|
|
|
|
|
|
|
} |
|
331
|
|
|
|
|
|
|
elsif ($lhs->isa('PPI::Structure::List')) { |
|
332
|
9
|
|
|
|
|
102
|
local $self->{ctx} = 'list'; |
|
333
|
9
|
|
|
|
|
24
|
@lhs = $self->_handle_list($lhs,is_lhs=>1); |
|
334
|
|
|
|
|
|
|
} |
|
335
|
0
|
|
|
|
|
0
|
else { confess "invalid assignment LHS "._errmsg($lhs) } # uncoverable statement |
|
336
|
|
|
|
|
|
|
|
|
337
|
245
|
100
|
|
|
|
518
|
local $self->{ctx} = $lhs_scalar ? 'scalar' : 'list'; |
|
338
|
245
|
|
|
|
|
427
|
my @rhs = $self->_handle_value($rhs); |
|
339
|
|
|
|
|
|
|
|
|
340
|
244
|
|
|
|
|
1391
|
for my $l (@lhs) { |
|
341
|
250
|
100
|
|
|
|
604
|
if (!defined($l)) ## no critic (ProhibitCascadingIfElse) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
342
|
1
|
|
|
|
|
2
|
{ shift @rhs } |
|
343
|
|
|
|
|
|
|
elsif ($l->{atype} eq '$') |
|
344
|
215
|
|
|
|
|
211
|
{ ${ $l->{ref} } = shift @rhs } |
|
|
215
|
|
|
|
|
451
|
|
|
345
|
|
|
|
|
|
|
elsif ($l->{atype} eq '@') { |
|
346
|
20
|
100
|
|
|
|
21
|
if (!defined ${$l->{ref}}) |
|
|
20
|
|
|
|
|
53
|
|
|
347
|
18
|
|
|
|
|
34
|
{ ${ $l->{ref} } = [@rhs] } |
|
|
18
|
|
|
|
|
24
|
|
|
348
|
|
|
|
|
|
|
else |
|
349
|
2
|
|
|
|
|
3
|
{ @{ ${ $l->{ref} } } = @rhs } |
|
|
2
|
|
|
|
|
2
|
|
|
|
2
|
|
|
|
|
7
|
|
|
350
|
20
|
|
|
|
|
33
|
last; # slurp |
|
351
|
|
|
|
|
|
|
} |
|
352
|
|
|
|
|
|
|
elsif ($l->{atype} eq '%') { |
|
353
|
14
|
100
|
|
|
|
15
|
if (!defined ${$l->{ref}}) |
|
|
14
|
|
|
|
|
29
|
|
|
354
|
12
|
|
|
|
|
26
|
{ ${ $l->{ref} } = {@rhs} } |
|
|
12
|
|
|
|
|
15
|
|
|
355
|
|
|
|
|
|
|
else |
|
356
|
2
|
|
|
|
|
3
|
{ %{ ${ $l->{ref} } } = @rhs } |
|
|
2
|
|
|
|
|
2
|
|
|
|
2
|
|
|
|
|
6
|
|
|
357
|
14
|
|
|
|
|
53
|
last; # slurp |
|
358
|
|
|
|
|
|
|
} |
|
359
|
0
|
|
|
|
|
0
|
else { confess "Possible internal error: can't assign to "._errmsg($l)." in\n"._errmsg($as) } # uncoverable statement |
|
360
|
|
|
|
|
|
|
} |
|
361
|
244
|
|
|
|
|
561
|
return; |
|
362
|
|
|
|
|
|
|
} |
|
363
|
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
# returns a list (if param is_lhs is true, list will consist of only _handle_symbol return values) |
|
365
|
|
|
|
|
|
|
sub _handle_list { ## no critic (ProhibitExcessComplexity) |
|
366
|
110
|
|
|
110
|
|
168
|
my ($self,$outerlist,%param) = @_; |
|
367
|
|
|
|
|
|
|
# NOTE this handles both () lists as well as the *contents* of {} and [] constructors |
|
368
|
110
|
50
|
|
|
|
234
|
confess "outerlist is undef?" unless $outerlist; |
|
369
|
110
|
50
|
66
|
|
|
554
|
confess "bad list class ".$outerlist->class |
|
370
|
|
|
|
|
|
|
unless $outerlist->isa('PPI::Structure::List') || $outerlist->isa('PPI::Structure::Constructor'); |
|
371
|
|
|
|
|
|
|
# We should already have been placed in list context |
|
372
|
110
|
50
|
|
|
|
614
|
confess "Internal error: Context is not list? Is \"$$self{ctx} \"at:\n"._errmsg($outerlist) |
|
373
|
|
|
|
|
|
|
unless $self->{ctx}=~/^list\b/; |
|
374
|
110
|
50
|
66
|
|
|
243
|
croak "can only handle a plain list on LHS" |
|
375
|
|
|
|
|
|
|
if $param{is_lhs} && !$outerlist->isa('PPI::Structure::List'); |
|
376
|
110
|
50
|
|
|
|
297
|
return unless $outerlist->schildren; # empty list |
|
377
|
|
|
|
|
|
|
# the first & only child of the outer list structure is a statement / expression |
|
378
|
110
|
|
|
|
|
1320
|
my $act_list = $outerlist->schild(0); |
|
379
|
110
|
50
|
66
|
|
|
1071
|
croak "Unsupported list\n"._errmsg($outerlist) |
|
|
|
|
33
|
|
|
|
|
|
380
|
|
|
|
|
|
|
unless $outerlist->schildren==1 && ($act_list->isa('PPI::Statement::Expression') || $act_list->class eq 'PPI::Statement'); |
|
381
|
110
|
50
|
|
|
|
1837
|
return unless $act_list->schildren; # empty list? |
|
382
|
110
|
|
|
|
|
1415
|
my @thelist; |
|
383
|
110
|
|
|
|
|
115
|
my $expect = 'item'; |
|
384
|
110
|
|
|
|
|
219
|
my $el = $act_list->schild(0); |
|
385
|
110
|
|
|
|
|
897
|
ELEMENT: while ($el) { |
|
386
|
482
|
100
|
|
|
|
5483
|
if ($expect eq 'item') { |
|
|
|
50
|
|
|
|
|
|
|
387
|
295
|
|
|
|
|
600
|
my $peek_next = $el->snext_sibling; |
|
388
|
295
|
|
100
|
|
|
4556
|
my $fat_comma_next = $peek_next && $peek_next->isa('PPI::Token::Operator') && $peek_next->content eq '=>'; |
|
389
|
295
|
100
|
|
|
|
896
|
if ($param{is_lhs}) { |
|
390
|
15
|
100
|
66
|
|
|
50
|
if ($el->isa('PPI::Token::Symbol')) |
|
|
|
100
|
66
|
|
|
|
|
|
391
|
13
|
|
|
|
|
22
|
{ push @thelist, $self->_handle_symbol($el) } |
|
392
|
|
|
|
|
|
|
elsif (!$fat_comma_next && $el->isa('PPI::Token::Word') && $el->literal eq 'undef') |
|
393
|
1
|
|
|
|
|
10
|
{ push @thelist, undef } |
|
394
|
|
|
|
|
|
|
else |
|
395
|
1
|
|
|
|
|
3
|
{ croak "Don't support this on LHS: "._errmsg($el) } |
|
396
|
|
|
|
|
|
|
} |
|
397
|
|
|
|
|
|
|
else { |
|
398
|
|
|
|
|
|
|
# handle fat comma autoquoting words |
|
399
|
280
|
100
|
100
|
|
|
1819
|
if ($fat_comma_next && $el->isa('PPI::Token::Word') && $el->literal=~/^\w+$/ ) |
|
|
|
100
|
100
|
|
|
|
|
|
400
|
29
|
|
|
|
|
349
|
{ push @thelist, $el->literal } |
|
401
|
|
|
|
|
|
|
elsif ($el->isa('PPI::Token::QuoteLike::Words')) # qw// in a list |
|
402
|
2
|
|
|
|
|
9
|
{ push @thelist, $el->literal } # here "literal" returns a list of words |
|
403
|
|
|
|
|
|
|
else { |
|
404
|
249
|
|
|
|
|
400
|
push @thelist, $self->_handle_value($el); |
|
405
|
|
|
|
|
|
|
# special case of do followed by BLOCKs |
|
406
|
249
|
50
|
100
|
|
|
2180
|
if ($el->isa('PPI::Token::Word') && $el->literal eq 'do' |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
407
|
|
|
|
|
|
|
&& $peek_next && $peek_next->isa('PPI::Structure::Block')) |
|
408
|
1
|
|
|
|
|
19
|
{ $el = $el->snext_sibling } # this will have been handled by _handle_value |
|
409
|
|
|
|
|
|
|
} |
|
410
|
|
|
|
|
|
|
} |
|
411
|
|
|
|
|
|
|
# special case of symbols followed by subscripts |
|
412
|
|
|
|
|
|
|
# Possible To-Do for Later: More generalized handling of multi-element list items? |
|
413
|
|
|
|
|
|
|
# Right now we have special handling of Symbol-Subscript and do-BLOCK pairs, if more special cases appear, |
|
414
|
|
|
|
|
|
|
# we should figure out a more generalized way of advancing our list pointer over the handled elements. |
|
415
|
294
|
100
|
100
|
|
|
1326
|
if ($el->isa('PPI::Token::Symbol') && $peek_next && $peek_next->isa('PPI::Structure::Subscript')) |
|
|
|
|
100
|
|
|
|
|
|
416
|
5
|
|
|
|
|
10
|
{ $el = $el->snext_sibling } # this will have been handled by _handle_symbol, called from _handle_value |
|
417
|
294
|
|
|
|
|
424
|
$expect = 'separator'; |
|
418
|
|
|
|
|
|
|
} |
|
419
|
|
|
|
|
|
|
elsif ($expect eq 'separator') { |
|
420
|
187
|
50
|
66
|
|
|
691
|
croak "Expected list separator, got "._errmsg($el) |
|
|
|
|
33
|
|
|
|
|
|
421
|
|
|
|
|
|
|
unless $el->isa('PPI::Token::Operator') |
|
422
|
|
|
|
|
|
|
&& ($el->content eq ',' || $el->content eq '=>'); |
|
423
|
187
|
|
|
|
|
1007
|
$expect = 'item'; |
|
424
|
|
|
|
|
|
|
} |
|
425
|
0
|
|
|
|
|
0
|
else { confess "really shouldn't happen, bad state $expect" } # uncoverable statement |
|
426
|
481
|
|
|
|
|
818
|
} continue { $el = $el->snext_sibling } |
|
427
|
109
|
|
|
|
|
1783
|
return @thelist; |
|
428
|
|
|
|
|
|
|
} |
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
# respects context and returns either a single value, or list if applicable |
|
431
|
|
|
|
|
|
|
sub _handle_value { ## no critic (ProhibitExcessComplexity) |
|
432
|
538
|
|
|
538
|
|
566
|
my ($self,$val) = @_; |
|
433
|
538
|
50
|
|
|
|
1169
|
confess "\$val is false" unless $val; |
|
434
|
538
|
100
|
100
|
|
|
2883
|
if ($val->isa('PPI::Token::Number')) ## no critic (ProhibitCascadingIfElse) |
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
435
|
154
|
|
|
|
|
357
|
{ return 0+$val->literal } |
|
436
|
|
|
|
|
|
|
elsif ($val->isa('PPI::Token::Quote')) |
|
437
|
233
|
|
|
|
|
371
|
{ return $self->_handle_quote($val) } |
|
438
|
|
|
|
|
|
|
elsif ($val->isa('PPI::Structure::Constructor')) |
|
439
|
77
|
|
|
|
|
151
|
{ return $self->_handle_struct($val) } |
|
440
|
|
|
|
|
|
|
elsif ($val->isa('PPI::Token::Word') && $val->literal eq 'undef') |
|
441
|
1
|
|
|
|
|
11
|
{ return undef } ## no critic (ProhibitExplicitReturnUndef) |
|
442
|
|
|
|
|
|
|
elsif ($val->isa('PPI::Token::Word') && $val->literal=~/^-\w+$/) |
|
443
|
4
|
|
|
|
|
80
|
{ return $val->literal } |
|
444
|
|
|
|
|
|
|
elsif ($val->isa('PPI::Token::Symbol')) { |
|
445
|
21
|
|
|
|
|
80
|
my $sym = $self->_handle_symbol($val); |
|
446
|
18
|
100
|
|
|
|
58
|
if ($sym->{atype} eq '$') { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
447
|
8
|
|
|
|
|
7
|
return ${ $sym->{ref} }; |
|
|
8
|
|
|
|
|
22
|
|
|
448
|
|
|
|
|
|
|
} |
|
449
|
|
|
|
|
|
|
elsif ($sym->{atype} eq '@') { |
|
450
|
1
|
|
|
|
|
3
|
return $self->{ctx}=~/^scalar\b/ |
|
451
|
1
|
|
|
|
|
2
|
? scalar(@{ ${ $sym->{ref} } }) |
|
|
4
|
|
|
|
|
43
|
|
|
452
|
5
|
100
|
|
|
|
13
|
: @{ ${ $sym->{ref} } }; |
|
|
4
|
|
|
|
|
6
|
|
|
453
|
|
|
|
|
|
|
} |
|
454
|
|
|
|
|
|
|
elsif ($sym->{atype} eq '%') { |
|
455
|
1
|
|
|
|
|
6
|
return $self->{ctx}=~/^scalar\b/ |
|
456
|
1
|
|
|
|
|
1
|
? scalar(%{ ${ $sym->{ref} } }) |
|
|
3
|
|
|
|
|
20
|
|
|
457
|
4
|
100
|
|
|
|
12
|
: %{ ${ $sym->{ref} } }; |
|
|
3
|
|
|
|
|
3
|
|
|
458
|
|
|
|
|
|
|
} |
|
459
|
1
|
|
|
|
|
144
|
else { confess "bad symbol $sym" } |
|
460
|
|
|
|
|
|
|
} |
|
461
|
|
|
|
|
|
|
elsif ($val->isa('PPI::Token::Word') && $val->literal eq 'do' |
|
462
|
|
|
|
|
|
|
&& $val->snext_sibling && $val->snext_sibling->isa('PPI::Structure::Block')) |
|
463
|
2
|
|
|
|
|
121
|
{ return $self->_handle_block($val->snext_sibling) } |
|
464
|
|
|
|
|
|
|
elsif ($val->isa('PPI::Structure::List')) { |
|
465
|
24
|
|
|
|
|
1056
|
my @l = do { |
|
466
|
|
|
|
|
|
|
# temporarily force list context to make _handle_list happy |
|
467
|
24
|
|
|
|
|
40
|
local $self->{ctx} = 'list'; |
|
468
|
24
|
|
|
|
|
45
|
$self->_handle_list($val); |
|
469
|
|
|
|
|
|
|
}; |
|
470
|
24
|
100
|
|
|
|
94
|
return $self->{ctx}=~/^scalar\b/ ? $l[-1] : @l; |
|
471
|
|
|
|
|
|
|
} |
|
472
|
|
|
|
|
|
|
elsif ($val->isa('PPI::Token::QuoteLike::Words')) { # qw// |
|
473
|
20
|
|
|
|
|
58
|
my @l = $val->literal; # returns a list of words |
|
474
|
20
|
100
|
|
|
|
209
|
return $self->{ctx}=~/^scalar\b/ ? $l[-1] : @l; |
|
475
|
|
|
|
|
|
|
} |
|
476
|
2
|
|
|
|
|
60
|
croak "Can't handle value "._errmsg($val); |
|
477
|
|
|
|
|
|
|
} |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
# returns a hashref representing the symbol (see code below for details) |
|
480
|
|
|
|
|
|
|
sub _handle_symbol { |
|
481
|
274
|
|
|
274
|
|
338
|
my ($self,$sym) = @_; |
|
482
|
274
|
50
|
|
|
|
595
|
confess "bad symbol" unless $sym->isa('PPI::Token::Symbol'); |
|
483
|
274
|
|
|
|
|
501
|
my $peek_next = $sym->snext_sibling; |
|
484
|
274
|
|
|
|
|
3718
|
my %rsym = ( name => $sym->symbol, atype => $sym->raw_type ); |
|
485
|
274
|
100
|
100
|
|
|
10482
|
if ($peek_next && $peek_next->isa('PPI::Structure::Subscript')) { |
|
486
|
18
|
|
|
|
|
40
|
my $sub = $self->_handle_subscript($peek_next); |
|
487
|
14
|
100
|
100
|
|
|
153
|
if ($sym->raw_type eq '$' && $sym->symbol_type eq '@' && $peek_next->braces eq '[]') { |
|
|
|
100
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
488
|
10
|
|
|
|
|
655
|
$rsym{ref} = \( $self->{out}{$sym->symbol}[$sub] ); |
|
489
|
10
|
|
|
|
|
467
|
$rsym{sub} = "[$sub]"; |
|
490
|
|
|
|
|
|
|
} |
|
491
|
|
|
|
|
|
|
elsif ($sym->raw_type eq '$' && $sym->symbol_type eq '%' && $peek_next->braces eq '{}') { |
|
492
|
2
|
|
|
|
|
273
|
$rsym{ref} = \( $self->{out}{$sym->symbol}{$sub} ); |
|
493
|
2
|
|
|
|
|
93
|
$rsym{sub} = "{$sub}"; |
|
494
|
|
|
|
|
|
|
} |
|
495
|
2
|
|
|
|
|
35
|
else { croak "Can't handle this subscript on this variable: "._errmsg($sym)._errmsg($peek_next) } |
|
496
|
|
|
|
|
|
|
} |
|
497
|
|
|
|
|
|
|
else { |
|
498
|
256
|
|
|
|
|
579
|
$rsym{ref} = \( $self->{out}{$sym->symbol} ); |
|
499
|
|
|
|
|
|
|
} |
|
500
|
268
|
|
|
|
|
6681
|
return \%rsym; |
|
501
|
|
|
|
|
|
|
} |
|
502
|
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
# returns a single value |
|
504
|
|
|
|
|
|
|
sub _handle_subscript { |
|
505
|
18
|
|
|
18
|
|
26
|
my ($self,$sub) = @_; |
|
506
|
18
|
50
|
|
|
|
49
|
confess "bad subscript" unless $sub->isa('PPI::Structure::Subscript'); |
|
507
|
18
|
|
|
|
|
50
|
my @sub_ch = $sub->schildren; |
|
508
|
18
|
50
|
33
|
|
|
208
|
croak "Expected subscript to contain a single expression\n"._errmsg($sub) |
|
509
|
|
|
|
|
|
|
unless @sub_ch==1 && $sub_ch[0]->isa('PPI::Statement::Expression'); |
|
510
|
18
|
|
|
|
|
45
|
my @subs = $sub_ch[0]->schildren; |
|
511
|
18
|
100
|
|
|
|
102
|
croak "Expected subscript to contain a single value\n"._errmsg($sub) |
|
512
|
|
|
|
|
|
|
unless @subs==1; |
|
513
|
|
|
|
|
|
|
# autoquoting in hash braces |
|
514
|
15
|
100
|
100
|
|
|
28
|
if ($sub->braces eq '{}' && $subs[0]->isa('PPI::Token::Word')) |
|
515
|
2
|
|
|
|
|
27
|
{ return $subs[0]->literal } |
|
516
|
|
|
|
|
|
|
else { |
|
517
|
13
|
|
|
|
|
104
|
local $self->{ctx} = 'scalar'; |
|
518
|
13
|
|
|
|
|
35
|
return $self->_handle_value($subs[0]); |
|
519
|
|
|
|
|
|
|
} |
|
520
|
|
|
|
|
|
|
} |
|
521
|
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
# returns arrayref or hashref |
|
523
|
|
|
|
|
|
|
sub _handle_struct { |
|
524
|
77
|
|
|
77
|
|
85
|
my ($self,$constr) = @_; |
|
525
|
77
|
50
|
|
|
|
200
|
confess "bad struct class ".$constr->class |
|
526
|
|
|
|
|
|
|
unless $constr->isa('PPI::Structure::Constructor'); |
|
527
|
77
|
|
|
|
|
123
|
local $self->{ctx} = 'list'; |
|
528
|
77
|
100
|
|
|
|
192
|
if ($constr->braces eq '[]') |
|
|
|
50
|
|
|
|
|
|
|
529
|
30
|
|
|
|
|
237
|
{ return [$self->_handle_list($constr)] } |
|
530
|
|
|
|
|
|
|
elsif ($constr->braces eq '{}') |
|
531
|
47
|
|
|
|
|
700
|
{ return {$self->_handle_list($constr)} } |
|
532
|
0
|
|
|
|
|
0
|
croak "Unsupported constructor\n"._errmsg($constr); # uncoverable statement |
|
533
|
|
|
|
|
|
|
} |
|
534
|
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
# handles the known PPI::Token::Quote subclasses |
|
536
|
|
|
|
|
|
|
# returns a single value |
|
537
|
|
|
|
|
|
|
sub _handle_quote { |
|
538
|
233
|
|
|
233
|
|
210
|
my ($self,$q) = @_; |
|
539
|
233
|
100
|
100
|
|
|
1358
|
if ( $q->isa('PPI::Token::Quote::Single') || $q->isa('PPI::Token::Quote::Literal') ) |
|
|
|
50
|
66
|
|
|
|
|
|
540
|
133
|
|
|
|
|
331
|
{ return $q->literal } |
|
541
|
|
|
|
|
|
|
elsif ( $q->isa('PPI::Token::Quote::Double') || $q->isa('PPI::Token::Quote::Interpolate') ) |
|
542
|
100
|
|
|
|
|
185
|
{ return $self->_handle_interpolate($q) } |
|
543
|
0
|
|
|
|
|
0
|
confess "unknown PPI::Token::Quote subclass ".$q->class; # uncoverable statement |
|
544
|
|
|
|
|
|
|
} |
|
545
|
|
|
|
|
|
|
# for use in _handle_quote; does very limited string interpolation |
|
546
|
|
|
|
|
|
|
# returns a single value |
|
547
|
|
|
|
|
|
|
sub _handle_interpolate { |
|
548
|
100
|
|
|
100
|
|
109
|
my ($self,$q) = @_; |
|
549
|
100
|
|
|
|
|
268
|
my $str = $q->string; |
|
550
|
|
|
|
|
|
|
# Perl (at least v5.20) doesn't allow trailing $, it does allow trailing @ |
|
551
|
100
|
100
|
|
|
|
789
|
croak "Final \$ should be \\\$ or \$name" if $str=~/\$$/; |
|
552
|
|
|
|
|
|
|
# Variables |
|
553
|
99
|
|
|
|
|
181
|
$str=~s{(?_fetch_interp_var($2)}eg; |
|
|
9
|
|
|
|
|
19
|
|
|
554
|
99
|
|
|
|
|
110
|
$str=~s{(?_fetch_interp_var($2.$3)}eg; |
|
|
2
|
|
|
|
|
16
|
|
|
555
|
99
|
100
|
|
|
|
263
|
croak "Don't support string interpolation of '$1' in '$str' at "._errmsg($q) |
|
556
|
|
|
|
|
|
|
if $str=~/(?
|
|
557
|
|
|
|
|
|
|
# Backslash escape sequences |
|
558
|
98
|
|
|
|
|
127
|
$str=~s{\\([0-7]{1,3}|x[0-9A-Fa-f]{2}|.)}{$self->_backsl($1)}eg; |
|
|
16
|
|
|
|
|
37
|
|
|
559
|
97
|
|
|
|
|
250
|
return $str; |
|
560
|
|
|
|
|
|
|
} |
|
561
|
|
|
|
|
|
|
my %_backsl_tbl = ( '\\'=>'\\', '$'=>'$', '"'=>'"', "'"=>"'", 'n'=>"\n", 'r'=>"\r", 't'=>"\t" ); |
|
562
|
|
|
|
|
|
|
sub _backsl { # for use in _handle_interpolate ONLY |
|
563
|
16
|
|
|
16
|
|
28
|
my ($self,$what) = @_; |
|
564
|
16
|
100
|
|
|
|
56
|
return chr(oct($what)) if $what=~/^[0-7]+$/; |
|
565
|
13
|
50
|
|
|
|
22
|
return chr(hex($1)) if $what=~/^x([0-9A-Fa-f]+)$/; ## no critic (ProhibitCaptureWithoutTest) |
|
566
|
13
|
100
|
|
|
|
47
|
return $_backsl_tbl{$what} if exists $_backsl_tbl{$what}; |
|
567
|
1
|
|
|
|
|
103
|
croak "Don't support escape sequence \"\\$what\""; |
|
568
|
|
|
|
|
|
|
} |
|
569
|
|
|
|
|
|
|
sub _fetch_interp_var { # for use in _handle_interpolate ONLY |
|
570
|
11
|
|
|
11
|
|
19
|
my ($self,$var) = @_; |
|
571
|
11
|
100
|
100
|
|
|
79
|
return $self->{out}{$var} |
|
572
|
|
|
|
|
|
|
if exists $self->{out}{$var} && defined $self->{out}{$var}; |
|
573
|
2
|
|
|
|
|
500
|
warnings::warnif("Use of uninitialized value $var in interpolation"); |
|
574
|
2
|
|
|
|
|
141
|
return ""; |
|
575
|
|
|
|
|
|
|
} |
|
576
|
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
1; |