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; |