| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# Copyright (c) 2012, cPanel, Inc. |
|
2
|
|
|
|
|
|
|
# All rights reserved. |
|
3
|
|
|
|
|
|
|
# http://cpanel.net/ |
|
4
|
|
|
|
|
|
|
# |
|
5
|
|
|
|
|
|
|
# This is free software; you can redistribute it and/or modify it under the same |
|
6
|
|
|
|
|
|
|
# terms as Perl itself. See the LICENSE file for further details. |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
package Mail::Alias::Reader::Token; |
|
9
|
|
|
|
|
|
|
|
|
10
|
5
|
|
|
5
|
|
25711
|
use strict; |
|
|
5
|
|
|
|
|
11
|
|
|
|
5
|
|
|
|
|
163
|
|
|
11
|
5
|
|
|
5
|
|
25
|
use warnings; |
|
|
5
|
|
|
|
|
11
|
|
|
|
5
|
|
|
|
|
121
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
5
|
|
|
5
|
|
26
|
use Carp; |
|
|
5
|
|
|
|
|
11
|
|
|
|
5
|
|
|
|
|
10711
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 NAME |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
Mail::Alias::Reader::Token |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
Mail::Alias::Reader::Token is not only the class represents an aliases(5) parser |
|
22
|
|
|
|
|
|
|
token, but also itself is returned by L as a representation |
|
23
|
|
|
|
|
|
|
of a mail alias destination. For the purposes of this documentation, only the |
|
24
|
|
|
|
|
|
|
public-facing methods which facilitate the usage of instances of this class |
|
25
|
|
|
|
|
|
|
shall be discussed. |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=cut |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
my @TOKEN_TYPES = ( |
|
30
|
|
|
|
|
|
|
[ 'T_COMMENT' => qr/#\s*(.*)$/ ], |
|
31
|
|
|
|
|
|
|
[ 'T_STRING' => qr/("(?:\\.|[^"\\]+)*")/ ], |
|
32
|
|
|
|
|
|
|
[ 'T_COMMA' => qr/,/ ], |
|
33
|
|
|
|
|
|
|
[ 'T_DIRECTIVE' => qr/:([^\:\s]+):([^\:\s,]*)/ ], |
|
34
|
|
|
|
|
|
|
[ 'T_COMMAND' => qr/\|(\S+)/ ], |
|
35
|
|
|
|
|
|
|
[ 'T_ADDRESS' => qr/([a-z0-9_\-@\.*]+)/i ], |
|
36
|
|
|
|
|
|
|
[ 'T_COLON' => qr/\:/ ], |
|
37
|
|
|
|
|
|
|
[ 'T_FILE' => qr/(\S+)/ ], |
|
38
|
|
|
|
|
|
|
[ 'T_WHITESPACE' => qr/\s+/ ], |
|
39
|
|
|
|
|
|
|
); |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
my @TOKEN_STRING_TYPES = ( |
|
42
|
|
|
|
|
|
|
[ 'T_DIRECTIVE' => qr/:([^\:\s]+):\s*(.*)/s ], |
|
43
|
|
|
|
|
|
|
[ 'T_COMMAND' => qr/\|(.*)/s ], |
|
44
|
|
|
|
|
|
|
[ 'T_ADDRESS' => qr/([^\/]+)/s ], |
|
45
|
|
|
|
|
|
|
[ 'T_FILE' => qr/(.*)/s ] |
|
46
|
|
|
|
|
|
|
); |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# |
|
49
|
|
|
|
|
|
|
# Mail::Alias::Reader::Token->new($type) |
|
50
|
|
|
|
|
|
|
# |
|
51
|
|
|
|
|
|
|
# Create a new mail alias parser token of the given type. This method isn't |
|
52
|
|
|
|
|
|
|
# actually meant to be called publically; rather, it is simply a shortcut to |
|
53
|
|
|
|
|
|
|
# create symbolic parser tokens that contain no data, but refer to a piece of |
|
54
|
|
|
|
|
|
|
# punctuation, or similar. |
|
55
|
|
|
|
|
|
|
# |
|
56
|
|
|
|
|
|
|
sub new { |
|
57
|
112
|
|
|
112
|
0
|
462055
|
my ( $class, $type ) = @_; |
|
58
|
|
|
|
|
|
|
|
|
59
|
112
|
|
|
|
|
966
|
return bless { 'type' => $type }, $class; |
|
60
|
|
|
|
|
|
|
} |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# |
|
63
|
|
|
|
|
|
|
# $token->isa(@types) |
|
64
|
|
|
|
|
|
|
# |
|
65
|
|
|
|
|
|
|
# Return true if the current token is of any of the types passed as an |
|
66
|
|
|
|
|
|
|
# argument. |
|
67
|
|
|
|
|
|
|
# |
|
68
|
|
|
|
|
|
|
sub isa { |
|
69
|
894
|
|
|
894
|
0
|
2427
|
my ( $self, @types ) = @_; |
|
70
|
|
|
|
|
|
|
|
|
71
|
894
|
|
|
|
|
1647
|
foreach my $type (@types) { |
|
72
|
1464
|
100
|
|
|
|
10429
|
return 1 if $self->{'type'} eq $type; |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
620
|
|
|
|
|
5039
|
return 0; |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# |
|
79
|
|
|
|
|
|
|
# $token->is_punct() |
|
80
|
|
|
|
|
|
|
# |
|
81
|
|
|
|
|
|
|
# Returns true if the current token represents a piece of punctuation, or |
|
82
|
|
|
|
|
|
|
# something that separates values, clauses, or declarations from one another. |
|
83
|
|
|
|
|
|
|
# |
|
84
|
|
|
|
|
|
|
sub is_punct { |
|
85
|
10
|
|
|
10
|
0
|
11310
|
return shift->isa(qw/T_BEGIN T_END T_COLON T_COMMA/); |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# |
|
89
|
|
|
|
|
|
|
# $token->is_value() |
|
90
|
|
|
|
|
|
|
# |
|
91
|
|
|
|
|
|
|
# Returns true if the current token represents a meaningful value recorded in |
|
92
|
|
|
|
|
|
|
# text, such as a mail transfer agent directive, a command to pass message to, |
|
93
|
|
|
|
|
|
|
# a local or remote mailing address, or a file to append messages to. |
|
94
|
|
|
|
|
|
|
# |
|
95
|
|
|
|
|
|
|
sub is_value { |
|
96
|
104
|
|
|
104
|
0
|
4778
|
return shift->isa(qw/T_DIRECTIVE T_COMMAND T_ADDRESS T_FILE/); |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=head1 DETERMINING MAIL DESTINATION TYPE |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
A variety of methods are provided to allow one to infer the type of a mail |
|
102
|
|
|
|
|
|
|
alias (parser token) returned. |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=over |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=item $destination->is_address() |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
Returns true if the mail destination described by the current token is a local |
|
109
|
|
|
|
|
|
|
part or fully qualified mail address. |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=cut |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub is_address { |
|
114
|
52
|
|
|
52
|
1
|
6108
|
return shift->isa('T_ADDRESS'); |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=item $destination->is_directive() |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
Returns true if the mail destination described by the current token is a |
|
120
|
|
|
|
|
|
|
mail transfer agent directive. |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=cut |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub is_directive { |
|
125
|
16
|
|
|
16
|
1
|
4258
|
return shift->isa('T_DIRECTIVE'); |
|
126
|
|
|
|
|
|
|
} |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=item $destination->is_command() |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Returns true if the mail destination described by the current token is a |
|
131
|
|
|
|
|
|
|
command to which mail messages should be piped. |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=cut |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub is_command { |
|
136
|
14
|
|
|
14
|
1
|
4168
|
return shift->isa('T_COMMAND'); |
|
137
|
|
|
|
|
|
|
} |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=item $destination->is_file() |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
Returns true if the mail destination described by the current token is a file |
|
142
|
|
|
|
|
|
|
to which mail messages should be appended. |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=back |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=cut |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub is_file { |
|
149
|
10
|
|
|
10
|
1
|
5940
|
return shift->isa('T_FILE'); |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=head1 CONVERTING THE MAIL DESTINATION TO A STRING |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=over |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=item $destination->value() |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
Returns a parsed and unescaped logical representation of the mail alias |
|
159
|
|
|
|
|
|
|
destination that was originally parsed to yield the current token object. |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=cut |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
sub value { |
|
164
|
7
|
|
|
7
|
1
|
4167
|
return shift->{'value'}; |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=item $destination->to_string() |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
Returns a string representation of the mail alias destination that was |
|
170
|
|
|
|
|
|
|
originally parsed to yield the current token object. |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=back |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=cut |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
sub to_string { |
|
177
|
10
|
|
|
10
|
1
|
5949
|
my ($self) = @_; |
|
178
|
|
|
|
|
|
|
|
|
179
|
10
|
|
|
|
|
84
|
my %SUBSTITUTIONS = ( |
|
180
|
|
|
|
|
|
|
"\r" => '\r', |
|
181
|
|
|
|
|
|
|
"\n" => '\n', |
|
182
|
|
|
|
|
|
|
"\t" => '\t', |
|
183
|
|
|
|
|
|
|
'"' => '\"' |
|
184
|
|
|
|
|
|
|
); |
|
185
|
|
|
|
|
|
|
|
|
186
|
10
|
|
|
|
|
23
|
my $value = $self->{'value'}; |
|
187
|
|
|
|
|
|
|
|
|
188
|
10
|
100
|
|
|
|
45
|
if ($value) { |
|
189
|
6
|
|
|
|
|
21
|
foreach my $search ( keys %SUBSTITUTIONS ) { |
|
190
|
24
|
|
|
|
|
377
|
$value =~ s/$search/$SUBSTITUTIONS{$search}/g; |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
# |
|
195
|
|
|
|
|
|
|
# Since not every token type has a "value", per se, lazy evaluation is |
|
196
|
|
|
|
|
|
|
# necessary to prevent a Perl runtime warning when evaluating the 'T_COMMENT' |
|
197
|
|
|
|
|
|
|
# part of this hash when dealing with tokens that are anything other than a |
|
198
|
|
|
|
|
|
|
# comment. |
|
199
|
|
|
|
|
|
|
# |
|
200
|
|
|
|
|
|
|
my %FORMATTERS = ( |
|
201
|
1
|
|
|
1
|
|
18
|
'T_COMMENT' => sub { "# $value" }, |
|
202
|
1
|
|
|
1
|
|
29
|
'T_COMMA' => sub { ',' }, |
|
203
|
1
|
|
|
1
|
|
13
|
'T_COLON' => sub { ':' }, |
|
204
|
1
|
|
|
1
|
|
12
|
'T_WHITESPACE' => sub { ' ' } |
|
205
|
10
|
|
|
|
|
134
|
); |
|
206
|
|
|
|
|
|
|
|
|
207
|
10
|
100
|
|
|
|
908
|
return $FORMATTERS{ $self->{'type'} }->() if exists $FORMATTERS{ $self->{'type'} }; |
|
208
|
|
|
|
|
|
|
|
|
209
|
6
|
|
|
|
|
9
|
my $ret; |
|
210
|
|
|
|
|
|
|
|
|
211
|
6
|
100
|
|
|
|
16
|
if ( $self->is_directive ) { |
|
|
|
100
|
|
|
|
|
|
|
212
|
2
|
|
|
|
|
7
|
$ret = ":$self->{'name'}:$value"; |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
elsif ( $self->is_command ) { |
|
215
|
2
|
|
|
|
|
31
|
$ret = "|$value"; |
|
216
|
|
|
|
|
|
|
} |
|
217
|
|
|
|
|
|
|
else { |
|
218
|
2
|
|
|
|
|
4
|
$ret = $value; |
|
219
|
|
|
|
|
|
|
} |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
# |
|
222
|
|
|
|
|
|
|
# If the data to be returned contains spaces, then wrap it with double quotes |
|
223
|
|
|
|
|
|
|
# before returning it to the user. |
|
224
|
|
|
|
|
|
|
# |
|
225
|
6
|
100
|
|
|
|
61
|
$ret =~ s/^(.*)$/"$1"/ if $ret =~ /\s/; |
|
226
|
|
|
|
|
|
|
|
|
227
|
6
|
|
|
|
|
91
|
return $ret; |
|
228
|
|
|
|
|
|
|
} |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# |
|
231
|
|
|
|
|
|
|
# Mail::Alias::Reader::Token->tokenize_for_types($buf, @types) |
|
232
|
|
|
|
|
|
|
# |
|
233
|
|
|
|
|
|
|
# Transform the given text buffer, $buf, into a series of tokens, based on the |
|
234
|
|
|
|
|
|
|
# rules passed in @types (defined near the top of this file). Returns an ARRAY |
|
235
|
|
|
|
|
|
|
# of tokens that were matched based on the rules in @types versus the input |
|
236
|
|
|
|
|
|
|
# buffer. |
|
237
|
|
|
|
|
|
|
# |
|
238
|
|
|
|
|
|
|
# As the token types are associated with their parsing rules, and are given in |
|
239
|
|
|
|
|
|
|
# an ordered manner, proper precedence can be followed and ambiguity in lexing |
|
240
|
|
|
|
|
|
|
# can be overcome. |
|
241
|
|
|
|
|
|
|
# |
|
242
|
|
|
|
|
|
|
# This method does not provide the main tokenizing interface; rather, it only |
|
243
|
|
|
|
|
|
|
# facilitates for the easy access of a single pass of tokenizing, and is called |
|
244
|
|
|
|
|
|
|
# by the Mail::Alias::Reader::Token->tokenize() method. |
|
245
|
|
|
|
|
|
|
# |
|
246
|
|
|
|
|
|
|
sub tokenize_for_types { |
|
247
|
41
|
|
|
41
|
0
|
167
|
my ( $class, $buf, @types ) = @_; |
|
248
|
41
|
|
|
|
|
55
|
my @tokens; |
|
249
|
|
|
|
|
|
|
|
|
250
|
41
|
|
|
|
|
165
|
match: while ($buf) { |
|
251
|
203
|
|
|
|
|
312
|
foreach my $type (@types) { |
|
252
|
1266
|
100
|
|
|
|
34442
|
next unless $buf =~ s/^$type->[1]//; |
|
253
|
|
|
|
|
|
|
|
|
254
|
203
|
|
|
|
|
1395
|
my $token = bless { |
|
255
|
|
|
|
|
|
|
'type' => $type->[0], |
|
256
|
|
|
|
|
|
|
}, $class; |
|
257
|
|
|
|
|
|
|
|
|
258
|
203
|
100
|
|
|
|
829
|
if ( $type->[0] eq 'T_DIRECTIVE' ) { |
|
259
|
2
|
|
|
|
|
5
|
@{$token}{qw(name value)} = ( $1, $2 ); |
|
|
2
|
|
|
|
|
21
|
|
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
else { |
|
262
|
201
|
|
|
|
|
859
|
$token->{'value'} = $1; |
|
263
|
|
|
|
|
|
|
} |
|
264
|
|
|
|
|
|
|
|
|
265
|
203
|
|
|
|
|
301
|
push @tokens, $token; |
|
266
|
|
|
|
|
|
|
|
|
267
|
203
|
|
|
|
|
639
|
next match; |
|
268
|
|
|
|
|
|
|
} |
|
269
|
|
|
|
|
|
|
} |
|
270
|
|
|
|
|
|
|
|
|
271
|
41
|
|
|
|
|
140
|
return \@tokens; |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# |
|
275
|
|
|
|
|
|
|
# Mail::Alias::Reader::Token->tokenize($buf) |
|
276
|
|
|
|
|
|
|
# |
|
277
|
|
|
|
|
|
|
# Returns an ARRAY of tokens parsed from the given text buffer. |
|
278
|
|
|
|
|
|
|
# |
|
279
|
|
|
|
|
|
|
# This method tokenizes in two stages; first, it performs a high-level sweep of |
|
280
|
|
|
|
|
|
|
# any statements not inside double quotes, though while grabbing double-quoted |
|
281
|
|
|
|
|
|
|
# statements and holding onto them for a later second pass. During this second |
|
282
|
|
|
|
|
|
|
# tokenization pass, performed for each double-quoted statement found and in the |
|
283
|
|
|
|
|
|
|
# order of first-stage tokenization, statements containing spaces are parsed. |
|
284
|
|
|
|
|
|
|
# |
|
285
|
|
|
|
|
|
|
# Since this method is intended to be used on a single line of input, a T_BEGIN |
|
286
|
|
|
|
|
|
|
# and T_END token comes as the first and the last token returned, respectively. |
|
287
|
|
|
|
|
|
|
# |
|
288
|
|
|
|
|
|
|
sub tokenize { |
|
289
|
38
|
|
|
38
|
0
|
7398
|
my ( $class, $buf ) = @_; |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
# |
|
292
|
|
|
|
|
|
|
# When parsing token data contained within double quotes, the following |
|
293
|
|
|
|
|
|
|
# escape sequence patterns and substitutions are iterated over for each |
|
294
|
|
|
|
|
|
|
# double quoted expression, performing unescaping where necessary. |
|
295
|
|
|
|
|
|
|
# |
|
296
|
38
|
|
|
|
|
287
|
my %WHITESPACE = ( |
|
297
|
|
|
|
|
|
|
'r' => "\r", |
|
298
|
|
|
|
|
|
|
'n' => "\n", |
|
299
|
|
|
|
|
|
|
't' => "\t" |
|
300
|
|
|
|
|
|
|
); |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
my @STRING_ESCAPE_SEQUENCES = ( |
|
303
|
2
|
|
|
2
|
|
17
|
[ qr/\\(0\d*)/ => sub { pack 'W', oct($1) } ], |
|
304
|
1
|
|
|
1
|
|
7
|
[ qr/\\(x[0-9a-f]+)/ => sub { pack 'W', hex("0$1") } ], |
|
305
|
3
|
|
|
3
|
|
14
|
[ qr/\\([rnt])/ => sub { $WHITESPACE{$1} } ], |
|
306
|
38
|
|
|
2
|
|
978
|
[ qr/\\([^rnt])/ => sub { $1 } ] |
|
|
2
|
|
|
|
|
10
|
|
|
307
|
|
|
|
|
|
|
); |
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
# |
|
310
|
|
|
|
|
|
|
# Perform first stage tokenization on the input. |
|
311
|
|
|
|
|
|
|
# |
|
312
|
38
|
|
|
|
|
194
|
my $tokens = $class->tokenize_for_types( $buf, @TOKEN_TYPES ); |
|
313
|
|
|
|
|
|
|
|
|
314
|
38
|
|
|
|
|
57
|
foreach my $token ( @{$tokens} ) { |
|
|
38
|
|
|
|
|
102
|
|
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
# |
|
317
|
|
|
|
|
|
|
# Perform second stage tokenization on any T_STRING tokens found. As the aliases(5) |
|
318
|
|
|
|
|
|
|
# format lacks a string literal type, a second pass is required to parse the quote |
|
319
|
|
|
|
|
|
|
# delimited string out for a more specific type. |
|
320
|
|
|
|
|
|
|
# |
|
321
|
200
|
100
|
|
|
|
384
|
if ( $token->isa('T_STRING') ) { |
|
322
|
3
|
|
|
|
|
23
|
$token->{'value'} =~ s/^"(.*)"$/$1/s; |
|
323
|
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
# |
|
325
|
|
|
|
|
|
|
# Parse for any escape sequences that may be present. |
|
326
|
|
|
|
|
|
|
# |
|
327
|
3
|
|
|
|
|
7
|
foreach my $sequence (@STRING_ESCAPE_SEQUENCES) { |
|
328
|
12
|
|
|
|
|
31
|
my ( $pattern, $subst ) = @{$sequence}; |
|
|
12
|
|
|
|
|
21
|
|
|
329
|
|
|
|
|
|
|
|
|
330
|
12
|
|
|
|
|
64
|
$token->{'value'} =~ s/$pattern/$subst->()/seg; |
|
|
8
|
|
|
|
|
12
|
|
|
331
|
|
|
|
|
|
|
} |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
# |
|
334
|
|
|
|
|
|
|
# Create a new token from the second pass parsing step for the string |
|
335
|
|
|
|
|
|
|
# contents, copying the data directly into the existing token (so as to |
|
336
|
|
|
|
|
|
|
# not lose the previous reference). |
|
337
|
|
|
|
|
|
|
# |
|
338
|
3
|
|
|
|
|
5
|
%{$token} = %{ $class->tokenize_for_types( $token->{'value'}, @TOKEN_STRING_TYPES )->[0] }; |
|
|
3
|
|
|
|
|
21
|
|
|
|
3
|
|
|
|
|
15
|
|
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
} |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
return [ |
|
343
|
38
|
|
|
|
|
179
|
$class->new('T_BEGIN'), |
|
344
|
38
|
|
|
|
|
173
|
@{$tokens}, |
|
345
|
|
|
|
|
|
|
$class->new('T_END') |
|
346
|
|
|
|
|
|
|
]; |
|
347
|
|
|
|
|
|
|
} |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
1; |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
__END__ |