line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Language::P::Lexer; |
2
|
|
|
|
|
|
|
|
3
|
90
|
|
|
90
|
|
563
|
use strict; |
|
90
|
|
|
|
|
215
|
|
|
90
|
|
|
|
|
4095
|
|
4
|
90
|
|
|
90
|
|
734
|
use warnings; |
|
90
|
|
|
|
|
173
|
|
|
90
|
|
|
|
|
3404
|
|
5
|
90
|
|
|
90
|
|
476
|
use base qw(Class::Accessor::Fast); |
|
90
|
|
|
|
|
189
|
|
|
90
|
|
|
|
|
9952
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
__PACKAGE__->mk_ro_accessors( qw(stream buffer tokens symbol_table |
8
|
|
|
|
|
|
|
file line _start_of_line _heredoc_lexer |
9
|
|
|
|
|
|
|
) ); |
10
|
|
|
|
|
|
|
__PACKAGE__->mk_accessors( qw(quote) ); |
11
|
|
|
|
|
|
|
|
12
|
90
|
|
|
90
|
|
56226
|
use Language::P::ParseTree qw(:all); |
|
90
|
|
|
|
|
302
|
|
|
90
|
|
|
|
|
129150
|
|
13
|
90
|
|
|
90
|
|
984
|
use Language::P::Keywords; |
|
90
|
|
|
|
|
200
|
|
|
90
|
|
|
|
|
42711
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our @TOKENS; |
16
|
|
|
|
|
|
|
BEGIN { |
17
|
90
|
|
|
90
|
|
9715
|
our @TOKENS = |
18
|
|
|
|
|
|
|
qw(T_ID T_FQ_ID T_SUB_ID T_EOF T_PACKAGE T_FILETEST |
19
|
|
|
|
|
|
|
T_PATTERN T_STRING T_NUMBER T_QUOTE T_OR T_XOR |
20
|
|
|
|
|
|
|
T_SEMICOLON T_COLON T_COMMA T_OPPAR T_CLPAR T_OPSQ T_CLSQ |
21
|
|
|
|
|
|
|
T_OPBRK T_CLBRK T_OPHASH T_OPAN T_CLPAN T_INTERR |
22
|
|
|
|
|
|
|
T_NOT T_SLESS T_CLAN T_SGREAT T_EQUAL T_LESSEQUAL T_SLESSEQUAL |
23
|
|
|
|
|
|
|
T_GREATEQUAL T_SGREATEQUAL T_EQUALEQUAL T_SEQUALEQUAL T_NOTEQUAL |
24
|
|
|
|
|
|
|
T_SNOTEQUAL T_SLASH T_BACKSLASH T_DOT T_DOTDOT T_DOTDOTDOT T_PLUS |
25
|
|
|
|
|
|
|
T_MINUS T_STAR T_DOLLAR T_PERCENT T_AT T_AMPERSAND T_PLUSPLUS |
26
|
|
|
|
|
|
|
T_MINUSMINUS T_ANDAND T_OROR T_ARYLEN T_ARROW T_MATCH T_NOTMATCH |
27
|
|
|
|
|
|
|
T_ANDANDLOW T_ORORLOW T_NOTLOW T_XORLOW T_CMP T_SCMP T_SSTAR T_POWER |
28
|
|
|
|
|
|
|
T_PLUSEQUAL T_MINUSEQUAL T_STAREQUAL T_SLASHEQUAL T_LABEL T_TILDE |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
T_CLASS_START T_CLASS_END T_CLASS T_QUANTIFIER T_ASSERTION T_ALTERNATE |
31
|
|
|
|
|
|
|
T_CLGROUP |
32
|
|
|
|
|
|
|
); |
33
|
|
|
|
|
|
|
}; |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
use constant |
36
|
7110
|
|
|
|
|
98512
|
{ X_NOTHING => 0, |
37
|
|
|
|
|
|
|
X_STATE => 1, |
38
|
|
|
|
|
|
|
X_TERM => 2, |
39
|
|
|
|
|
|
|
X_OPERATOR => 3, |
40
|
|
|
|
|
|
|
X_BLOCK => 4, |
41
|
|
|
|
|
|
|
X_REF => 5, |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
O_POS => 0, |
44
|
|
|
|
|
|
|
O_TYPE => 1, |
45
|
|
|
|
|
|
|
O_VALUE => 2, |
46
|
|
|
|
|
|
|
O_ID_TYPE => 3, |
47
|
|
|
|
|
|
|
O_FT_OP => 3, |
48
|
|
|
|
|
|
|
O_QS_INTERPOLATE => 3, |
49
|
|
|
|
|
|
|
O_QS_BUFFER => 4, |
50
|
|
|
|
|
|
|
O_RX_REST => 3, |
51
|
|
|
|
|
|
|
O_RX_SECOND_HALF => 5, |
52
|
|
|
|
|
|
|
O_RX_FLAGS => 6, |
53
|
|
|
|
|
|
|
O_RX_INTERPOLATED => 7, |
54
|
|
|
|
|
|
|
O_NUM_FLAGS => 3, |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
LEX_NO_PACKAGE => 1, |
57
|
|
|
|
|
|
|
|
58
|
90
|
|
|
|
|
789
|
map { $TOKENS[$_] => $_ + 1 } 0 .. $#TOKENS, |
59
|
90
|
|
|
90
|
|
596
|
}; |
|
90
|
|
|
|
|
205
|
|
60
|
|
|
|
|
|
|
|
61
|
90
|
|
|
90
|
|
680
|
use Exporter qw(import); |
|
90
|
|
|
|
|
190
|
|
|
90
|
|
|
|
|
1248652
|
|
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
our @EXPORT_OK = |
64
|
|
|
|
|
|
|
( qw(X_NOTHING X_STATE X_TERM X_OPERATOR X_BLOCK X_REF |
65
|
|
|
|
|
|
|
O_POS O_TYPE O_VALUE O_ID_TYPE O_FT_OP O_QS_INTERPOLATE O_QS_BUFFER |
66
|
|
|
|
|
|
|
O_RX_REST O_RX_SECOND_HALF O_RX_FLAGS O_RX_INTERPOLATED O_NUM_FLAGS |
67
|
|
|
|
|
|
|
LEX_NO_PACKAGE |
68
|
|
|
|
|
|
|
), @TOKENS ); |
69
|
|
|
|
|
|
|
our %EXPORT_TAGS = |
70
|
|
|
|
|
|
|
( all => \@EXPORT_OK, |
71
|
|
|
|
|
|
|
); |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub new { |
74
|
249
|
|
|
249
|
1
|
3235
|
my( $class, $args ) = @_; |
75
|
249
|
|
|
|
|
1222
|
my $self = $class->SUPER::new( $args ); |
76
|
249
|
|
100
|
|
|
3645
|
my $a = delete $self->{string} || ""; |
77
|
|
|
|
|
|
|
|
78
|
249
|
100
|
|
|
|
1249
|
$self->{buffer} = ref $a ? $a : \$a; |
79
|
249
|
|
|
|
|
676
|
$self->{tokens} = []; |
80
|
249
|
|
|
|
|
551
|
$self->{brackets} = 0; |
81
|
249
|
|
|
|
|
579
|
$self->{pending_brackets} = []; |
82
|
249
|
|
|
|
|
651
|
$self->{line} = 1; |
83
|
249
|
|
|
|
|
519
|
$self->{_start_of_line} = 1; |
84
|
249
|
|
|
|
|
1060
|
$self->{pos} = [ $self->file, $self->line ]; |
85
|
|
|
|
|
|
|
|
86
|
249
|
|
|
|
|
3026
|
return $self; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub peek { |
90
|
3134
|
|
|
3134
|
0
|
15194
|
my( $self, $expect ) = ( @_, X_NOTHING ); |
91
|
3134
|
|
|
|
|
6502
|
my $token = $self->lex( $expect ); |
92
|
|
|
|
|
|
|
|
93
|
3134
|
|
|
|
|
12394
|
$self->unlex( $token ); |
94
|
|
|
|
|
|
|
|
95
|
3134
|
|
|
|
|
17615
|
return $token; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub unlex { |
99
|
4949
|
|
|
4949
|
0
|
11499
|
my( $self, $token ) = @_; |
100
|
|
|
|
|
|
|
|
101
|
4949
|
|
|
|
|
5472
|
push @{$self->tokens}, $token; |
|
4949
|
|
|
|
|
11446
|
|
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
my %ops = |
105
|
|
|
|
|
|
|
( ';' => T_SEMICOLON, |
106
|
|
|
|
|
|
|
':' => T_COLON, |
107
|
|
|
|
|
|
|
',' => T_COMMA, |
108
|
|
|
|
|
|
|
'=>' => T_COMMA, |
109
|
|
|
|
|
|
|
'(' => T_OPPAR, |
110
|
|
|
|
|
|
|
')' => T_CLPAR, |
111
|
|
|
|
|
|
|
'[' => T_OPSQ, |
112
|
|
|
|
|
|
|
']' => T_CLSQ, |
113
|
|
|
|
|
|
|
'{' => T_OPBRK, |
114
|
|
|
|
|
|
|
'}' => T_CLBRK, |
115
|
|
|
|
|
|
|
'?' => T_INTERR, |
116
|
|
|
|
|
|
|
'!' => T_NOT, |
117
|
|
|
|
|
|
|
'<' => T_OPAN, |
118
|
|
|
|
|
|
|
'lt' => T_SLESS, |
119
|
|
|
|
|
|
|
'>' => T_CLAN, |
120
|
|
|
|
|
|
|
'gt' => T_SGREAT, |
121
|
|
|
|
|
|
|
'=' => T_EQUAL, |
122
|
|
|
|
|
|
|
'<=' => T_LESSEQUAL, |
123
|
|
|
|
|
|
|
'le' => T_SLESSEQUAL, |
124
|
|
|
|
|
|
|
'>=' => T_GREATEQUAL, |
125
|
|
|
|
|
|
|
'ge' => T_SGREATEQUAL, |
126
|
|
|
|
|
|
|
'==' => T_EQUALEQUAL, |
127
|
|
|
|
|
|
|
'eq' => T_SEQUALEQUAL, |
128
|
|
|
|
|
|
|
'!=' => T_NOTEQUAL, |
129
|
|
|
|
|
|
|
'ne' => T_SNOTEQUAL, |
130
|
|
|
|
|
|
|
'<=>' => T_CMP, |
131
|
|
|
|
|
|
|
'cmp' => T_SCMP, |
132
|
|
|
|
|
|
|
'/' => T_SLASH, |
133
|
|
|
|
|
|
|
'\\' => T_BACKSLASH, |
134
|
|
|
|
|
|
|
'.' => T_DOT, |
135
|
|
|
|
|
|
|
'..' => T_DOTDOT, |
136
|
|
|
|
|
|
|
'...' => T_DOTDOTDOT, |
137
|
|
|
|
|
|
|
'~' => T_TILDE, |
138
|
|
|
|
|
|
|
'+' => T_PLUS, |
139
|
|
|
|
|
|
|
'-' => T_MINUS, |
140
|
|
|
|
|
|
|
'*' => T_STAR, |
141
|
|
|
|
|
|
|
'x' => T_SSTAR, |
142
|
|
|
|
|
|
|
'$' => T_DOLLAR, |
143
|
|
|
|
|
|
|
'%' => T_PERCENT, |
144
|
|
|
|
|
|
|
'**' => T_POWER, |
145
|
|
|
|
|
|
|
'@' => T_AT, |
146
|
|
|
|
|
|
|
'&' => T_AMPERSAND, |
147
|
|
|
|
|
|
|
'|' => T_OR, |
148
|
|
|
|
|
|
|
'^' => T_XOR, |
149
|
|
|
|
|
|
|
'++' => T_PLUSPLUS, |
150
|
|
|
|
|
|
|
'--' => T_MINUSMINUS, |
151
|
|
|
|
|
|
|
'&&' => T_ANDAND, |
152
|
|
|
|
|
|
|
'||' => T_OROR, |
153
|
|
|
|
|
|
|
'$#' => T_ARYLEN, |
154
|
|
|
|
|
|
|
'->' => T_ARROW, |
155
|
|
|
|
|
|
|
'=~' => T_MATCH, |
156
|
|
|
|
|
|
|
'!~' => T_NOTMATCH, |
157
|
|
|
|
|
|
|
'and' => T_ANDANDLOW, |
158
|
|
|
|
|
|
|
'or' => T_ORORLOW, |
159
|
|
|
|
|
|
|
'not' => T_NOTLOW, |
160
|
|
|
|
|
|
|
'xor' => T_XORLOW, |
161
|
|
|
|
|
|
|
); |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
my %filetest = |
164
|
|
|
|
|
|
|
( r => OP_FT_EREADABLE, |
165
|
|
|
|
|
|
|
w => OP_FT_EWRITABLE, |
166
|
|
|
|
|
|
|
x => OP_FT_EEXECUTABLE, |
167
|
|
|
|
|
|
|
o => OP_FT_EOWNED, |
168
|
|
|
|
|
|
|
R => OP_FT_RREADABLE, |
169
|
|
|
|
|
|
|
W => OP_FT_RWRITABLE, |
170
|
|
|
|
|
|
|
X => OP_FT_REXECUTABLE, |
171
|
|
|
|
|
|
|
O => OP_FT_ROWNED, |
172
|
|
|
|
|
|
|
e => OP_FT_EXISTS, |
173
|
|
|
|
|
|
|
z => OP_FT_EMPTY, |
174
|
|
|
|
|
|
|
s => OP_FT_NONEMPTY, |
175
|
|
|
|
|
|
|
f => OP_FT_ISFILE, |
176
|
|
|
|
|
|
|
d => OP_FT_ISDIR, |
177
|
|
|
|
|
|
|
l => OP_FT_ISSYMLINK, |
178
|
|
|
|
|
|
|
p => OP_FT_ISPIPE, |
179
|
|
|
|
|
|
|
S => OP_FT_ISSOCKET, |
180
|
|
|
|
|
|
|
b => OP_FT_ISBLOCKSPECIAL, |
181
|
|
|
|
|
|
|
c => OP_FT_ISCHARSPECIAL, |
182
|
|
|
|
|
|
|
t => OP_FT_ISTTY, |
183
|
|
|
|
|
|
|
u => OP_FT_SETUID, |
184
|
|
|
|
|
|
|
g => OP_FT_SETGID, |
185
|
|
|
|
|
|
|
k => OP_FT_STICKY, |
186
|
|
|
|
|
|
|
T => OP_FT_ISASCII, |
187
|
|
|
|
|
|
|
B => OP_FT_ISBINARY, |
188
|
|
|
|
|
|
|
M => OP_FT_MTIME, |
189
|
|
|
|
|
|
|
A => OP_FT_ATIME, |
190
|
|
|
|
|
|
|
C => OP_FT_CTIME, |
191
|
|
|
|
|
|
|
); |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
my %quoted_chars = |
194
|
|
|
|
|
|
|
( 'n' => "\n", |
195
|
|
|
|
|
|
|
't' => "\t", |
196
|
|
|
|
|
|
|
'r' => "\r", |
197
|
|
|
|
|
|
|
'f' => "\f", |
198
|
|
|
|
|
|
|
'b' => "\b", |
199
|
|
|
|
|
|
|
'a' => "\a", |
200
|
|
|
|
|
|
|
'e' => "\e", |
201
|
|
|
|
|
|
|
); |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
my %quoted_pattern = |
204
|
|
|
|
|
|
|
( w => [ T_CLASS, 'WORDS' ], |
205
|
|
|
|
|
|
|
W => [ T_CLASS, 'NON_WORDS' ], |
206
|
|
|
|
|
|
|
s => [ T_CLASS, 'SPACES' ], |
207
|
|
|
|
|
|
|
S => [ T_CLASS, 'NOT_SPACES' ], |
208
|
|
|
|
|
|
|
d => [ T_CLASS, 'DIGITS' ], |
209
|
|
|
|
|
|
|
D => [ T_CLASS, 'NOT_DIGITS' ], |
210
|
|
|
|
|
|
|
b => [ T_ASSERTION, 'WORD_BOUNDARY' ], |
211
|
|
|
|
|
|
|
B => [ T_ASSERTION, 'NON_WORD_BOUNDARY' ], |
212
|
|
|
|
|
|
|
A => [ T_ASSERTION, 'BEGINNING' ], |
213
|
|
|
|
|
|
|
Z => [ T_ASSERTION, 'END_OR_NEWLINE' ], |
214
|
|
|
|
|
|
|
z => [ T_ASSERTION, 'END' ], |
215
|
|
|
|
|
|
|
G => [ T_ASSERTION, 'POS' ], |
216
|
|
|
|
|
|
|
); |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
my %pattern_special = |
219
|
|
|
|
|
|
|
( '^' => [ T_ASSERTION, 'START_SPECIAL' ], |
220
|
|
|
|
|
|
|
'$' => [ T_ASSERTION, 'END_SPECIAL' ], |
221
|
|
|
|
|
|
|
'*' => [ T_QUANTIFIER, 0, -1, 1 ], |
222
|
|
|
|
|
|
|
'+' => [ T_QUANTIFIER, 1, -1, 1 ], |
223
|
|
|
|
|
|
|
'?' => [ T_QUANTIFIER, 0, 1, 1 ], |
224
|
|
|
|
|
|
|
'*?' => [ T_QUANTIFIER, 0, -1, 0 ], |
225
|
|
|
|
|
|
|
'+?' => [ T_QUANTIFIER, 1, -1, 0 ], |
226
|
|
|
|
|
|
|
'??' => [ T_QUANTIFIER, 0, 1, 0 ], |
227
|
|
|
|
|
|
|
')' => [ T_CLGROUP ], |
228
|
|
|
|
|
|
|
'|' => [ T_ALTERNATE ], |
229
|
|
|
|
|
|
|
'[' => [ T_CLASS_START ], |
230
|
|
|
|
|
|
|
']' => [ T_CLASS_END ], |
231
|
|
|
|
|
|
|
); |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub _skip_space { |
234
|
2517
|
|
|
2517
|
|
3209
|
my( $self ) = @_; |
235
|
2517
|
|
|
|
|
7876
|
my $buffer = $self->buffer; |
236
|
2517
|
|
|
|
|
9895
|
my $retval = ''; |
237
|
2517
|
|
|
|
|
3136
|
my $reset_pos = 0; |
238
|
|
|
|
|
|
|
|
239
|
2517
|
|
|
|
|
2863
|
for(;;) { |
240
|
3073
|
100
|
|
|
|
8874
|
$self->_fill_buffer unless length $$buffer; |
241
|
3073
|
100
|
|
|
|
6313
|
return unless length $$buffer; |
242
|
|
|
|
|
|
|
|
243
|
3009
|
100
|
66
|
|
|
15181
|
if( $self->{_start_of_line} |
244
|
|
|
|
|
|
|
&& $$buffer =~ s/^#[ \t]*line[ \t]+([0-9]+)(?:[ \t]+"([^"]+)")?[ \t]*[\r\n]// ) { |
245
|
1
|
|
|
|
|
4
|
$self->{line} = $1; |
246
|
1
|
50
|
|
|
|
7
|
$self->{file} = $2 if $2; |
247
|
1
|
|
|
|
|
2
|
$reset_pos = 1; |
248
|
1
|
|
|
|
|
38
|
next; |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
3008
|
50
|
66
|
|
|
15709
|
$$buffer =~ s/^([ \t]+)// && defined wantarray and $retval .= $1; |
252
|
3008
|
100
|
|
|
|
8799
|
if( $$buffer =~ s/^([\r\n])// ) { |
253
|
536
|
50
|
|
|
|
1337
|
$retval .= $1 if defined wantarray; |
254
|
536
|
|
|
|
|
901
|
$self->{_start_of_line} = 1; |
255
|
536
|
|
|
|
|
760
|
++$self->{line}; |
256
|
536
|
|
|
|
|
630
|
$reset_pos = 1; |
257
|
536
|
|
|
|
|
759
|
next; |
258
|
|
|
|
|
|
|
} |
259
|
2472
|
100
|
|
|
|
6373
|
if( $$buffer =~ s/^(#.*\n)// ) { |
260
|
19
|
50
|
|
|
|
75
|
$retval .= $1 if defined wantarray; |
261
|
19
|
|
|
|
|
49
|
$self->{_start_of_line} = 1; |
262
|
19
|
|
|
|
|
44
|
++$self->{line}; |
263
|
19
|
|
|
|
|
34
|
$reset_pos = 1; |
264
|
19
|
|
|
|
|
47
|
next; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
2453
|
50
|
|
|
|
5515
|
last if length $$buffer; |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
2453
|
100
|
|
|
|
4284
|
if( $reset_pos ) { |
271
|
372
|
|
|
|
|
1268
|
$self->{pos} = [ $self->{file}, $self->{line} ]; |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
2453
|
|
|
|
|
4763
|
return $retval; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# taken from intuit_more in toke.c |
278
|
|
|
|
|
|
|
sub _character_class_insanity { |
279
|
0
|
|
|
0
|
|
0
|
my( $self ) = @_; |
280
|
0
|
|
|
|
|
0
|
my $buffer = $self->buffer; |
281
|
|
|
|
|
|
|
|
282
|
0
|
0
|
|
|
|
0
|
if( $$buffer =~ /^\]|^\^/ ) { |
283
|
0
|
|
|
|
|
0
|
return 1; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
0
|
|
|
|
|
0
|
my( $t ) = $$buffer =~ /^(.*\])/; |
287
|
0
|
|
|
|
|
0
|
my $w = 2; |
288
|
0
|
|
|
|
|
0
|
my( $un_char, $last_un_char, @seen ) = ( 255 ); |
289
|
|
|
|
|
|
|
|
290
|
0
|
0
|
|
|
|
0
|
return 1 if !defined $t; |
291
|
|
|
|
|
|
|
|
292
|
0
|
0
|
|
|
|
0
|
if( $t =~ /^\$/ ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
293
|
0
|
|
|
|
|
0
|
$w -= 3; |
294
|
|
|
|
|
|
|
} elsif( $t =~ /^[0-9][0-9]\]/ ) { |
295
|
0
|
|
|
|
|
0
|
$w -= 10 |
296
|
|
|
|
|
|
|
} elsif( $t =~ /^[0-9]\]/ ) { |
297
|
0
|
|
|
|
|
0
|
$w -= 100; |
298
|
|
|
|
|
|
|
} elsif( $t =~ /^\$\w+/ ) { |
299
|
|
|
|
|
|
|
# HACK, not in original |
300
|
0
|
|
|
|
|
0
|
$w -= 100; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
0
|
|
|
|
|
0
|
for(;;) { |
304
|
0
|
|
|
|
|
0
|
last; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
0
|
0
|
|
|
|
0
|
return $w >= 0 ? 1 : 0; |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
# taken from intuit_more in toke.c |
311
|
|
|
|
|
|
|
sub _quoted_code_lookahead { |
312
|
32
|
|
|
32
|
|
54
|
my( $self ) = @_; |
313
|
32
|
|
|
|
|
98
|
my $buffer = $self->buffer; |
314
|
|
|
|
|
|
|
|
315
|
32
|
50
|
|
|
|
319
|
if( $$buffer =~ s/^->([{[])// ) { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
316
|
0
|
|
|
|
|
0
|
++$self->{brackets}; |
317
|
0
|
|
|
|
|
0
|
$self->unlex( [ $self->{pos}, $ops{$1}, $1 ] ); |
318
|
0
|
|
|
|
|
0
|
$self->unlex( [ $self->{pos}, T_ARROW, '->' ] ); |
319
|
|
|
|
|
|
|
} elsif( $$buffer =~ s/^{// ) { |
320
|
0
|
0
|
|
|
|
0
|
if( !$self->quote->{interpolated_pattern} ) { |
|
|
0
|
|
|
|
|
|
321
|
0
|
|
|
|
|
0
|
++$self->{brackets}; |
322
|
0
|
|
|
|
|
0
|
$self->unlex( [ $self->{pos}, T_OPBRK, '{' ] ); |
323
|
|
|
|
|
|
|
} elsif( $$buffer =~ /^[0-9]+,[0-9]*}/ ) { |
324
|
0
|
|
|
|
|
0
|
die 'Quantifier!'; |
325
|
|
|
|
|
|
|
} else { |
326
|
0
|
|
|
|
|
0
|
++$self->{brackets}; |
327
|
0
|
|
|
|
|
0
|
$self->unlex( [ $self->{pos}, T_OPBRK, '{' ] ); |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
} elsif( $$buffer =~ s/^\[// ) { |
330
|
3
|
50
|
|
|
|
14
|
if( !$self->quote->{interpolated_pattern} ) { |
331
|
3
|
|
|
|
|
27
|
++$self->{brackets}; |
332
|
3
|
|
|
|
|
17
|
$self->unlex( [ $self->{pos}, T_OPSQ, '[' ] ); |
333
|
|
|
|
|
|
|
} else { |
334
|
0
|
0
|
|
|
|
0
|
if( _character_class_insanity( $self ) ) { |
335
|
0
|
|
|
|
|
0
|
$$buffer = '[' . $$buffer; |
336
|
0
|
|
|
|
|
0
|
my $token = $self->lex_quote; |
337
|
0
|
|
|
|
|
0
|
$self->unlex( $token ); |
338
|
|
|
|
|
|
|
} else { |
339
|
0
|
|
|
|
|
0
|
++$self->{brackets}; |
340
|
0
|
|
|
|
|
0
|
$self->unlex( [ $self->{pos}, T_OPSQ, '[' ] ); |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
} else { |
344
|
29
|
|
|
|
|
73
|
my $token = $self->lex_quote; |
345
|
29
|
|
|
|
|
70
|
$self->unlex( $token ); |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
sub lex_pattern_group { |
350
|
0
|
|
|
0
|
0
|
0
|
my( $self ) = @_; |
351
|
0
|
|
|
|
|
0
|
my $buffer = $self->buffer; |
352
|
|
|
|
|
|
|
|
353
|
0
|
0
|
|
|
|
0
|
die unless length $$buffer; # no whitespace allowed after '(?' |
354
|
|
|
|
|
|
|
|
355
|
0
|
0
|
|
|
|
0
|
$$buffer =~ s/^(\#|:|[imsx]*\-[imsx]*:?|!|=|<=|)//x |
356
|
|
|
|
|
|
|
or die "Invalid character after (?"; |
357
|
|
|
|
|
|
|
|
358
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_PATTERN, $1 ]; |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
sub lex_charclass { |
362
|
0
|
|
|
0
|
0
|
0
|
my( $self ) = @_; |
363
|
|
|
|
|
|
|
|
364
|
0
|
|
|
|
|
0
|
my $buffer = $self->buffer; |
365
|
0
|
|
|
|
|
0
|
my $c = substr $$buffer, 0, 1, ''; |
366
|
0
|
0
|
|
|
|
0
|
if( $c eq '\\' ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
367
|
0
|
|
|
|
|
0
|
my $qc = substr $$buffer, 0, 1, ''; |
368
|
|
|
|
|
|
|
|
369
|
0
|
0
|
|
|
|
0
|
if( my $qp = $quoted_pattern{$qc} ) { |
370
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, $qp->[0], $qp->[1] ]; |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_STRING, $qc ]; |
374
|
|
|
|
|
|
|
} elsif( $c eq '-' ) { |
375
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_MINUS, '-' ]; |
376
|
|
|
|
|
|
|
} elsif( $c eq ']' ) { |
377
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_CLASS_END ]; |
378
|
|
|
|
|
|
|
} else { |
379
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_STRING, $c ]; |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub lex_quote { |
384
|
501
|
|
|
501
|
0
|
2388
|
my( $self ) = @_; |
385
|
|
|
|
|
|
|
|
386
|
501
|
100
|
|
|
|
570
|
return pop @{$self->tokens} if @{$self->tokens}; |
|
249
|
|
|
|
|
1824
|
|
|
501
|
|
|
|
|
1379
|
|
387
|
|
|
|
|
|
|
|
388
|
252
|
|
|
|
|
1854
|
my $buffer = $self->buffer; |
389
|
252
|
|
|
|
|
1015
|
my $v = ''; |
390
|
252
|
|
|
|
|
298
|
for(;;) { |
391
|
423
|
100
|
|
|
|
934
|
unless( length $$buffer ) { |
392
|
187
|
100
|
|
|
|
557
|
if( length $v ) { |
393
|
171
|
|
|
|
|
912
|
$self->unlex( [ $self->{pos}, T_EOF, '' ] ); |
394
|
171
|
|
|
|
|
2084
|
return [ $self->{pos}, T_STRING, $v, 1 ]; |
395
|
|
|
|
|
|
|
} else { |
396
|
16
|
|
|
|
|
80
|
return [ $self->{pos}, T_EOF, '' ]; |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
236
|
|
|
|
|
296
|
my $to_return; |
401
|
236
|
|
|
|
|
921
|
my $pattern = $self->quote->{pattern}; |
402
|
236
|
|
|
|
|
1491
|
my $interpolated_pattern = $self->quote->{interpolated_pattern}; |
403
|
236
|
|
|
|
|
1323
|
while( length $$buffer ) { |
404
|
1254
|
|
|
|
|
2178
|
my $c = substr $$buffer, 0, 1, ''; |
405
|
|
|
|
|
|
|
|
406
|
1254
|
100
|
66
|
|
|
6933
|
if( $pattern || $interpolated_pattern ) { |
407
|
91
|
100
|
66
|
|
|
746
|
if( $c eq '\\' ) { |
|
|
100
|
66
|
|
|
|
|
|
|
100
|
|
|
|
|
|
408
|
1
|
|
|
|
|
4
|
my $qc = substr $$buffer, 0, 1; |
409
|
|
|
|
|
|
|
|
410
|
1
|
50
|
|
|
|
7
|
if( my $qp = $quoted_pattern{$qc} ) { |
411
|
0
|
|
|
|
|
0
|
substr $$buffer, 0, 1, ''; # eat character |
412
|
0
|
0
|
|
|
|
0
|
if( $pattern ) { |
413
|
0
|
|
|
|
|
0
|
$to_return = [ $self->{pos}, T_PATTERN, $qc, $qp ]; |
414
|
|
|
|
|
|
|
} else { |
415
|
0
|
|
|
|
|
0
|
$v .= $c . $qc; |
416
|
0
|
|
|
|
|
0
|
next; |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
} elsif( $c eq '(' && !$interpolated_pattern ) { |
420
|
7
|
|
|
|
|
16
|
my $nc = substr $$buffer, 0, 1; |
421
|
|
|
|
|
|
|
|
422
|
7
|
50
|
|
|
|
16
|
if( $nc eq '?' ) { |
423
|
0
|
|
|
|
|
0
|
substr $$buffer, 0, 1, ''; # eat character |
424
|
0
|
|
|
|
|
0
|
$to_return = [ $self->{pos}, T_PATTERN, '(?' ]; |
425
|
|
|
|
|
|
|
} else { |
426
|
7
|
|
|
|
|
29
|
$to_return = [ $self->{pos}, T_PATTERN, '(' ]; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
} elsif( !$interpolated_pattern |
429
|
|
|
|
|
|
|
and my $special = $pattern_special{$c} ) { |
430
|
|
|
|
|
|
|
# check nongreedy quantifiers |
431
|
29
|
100
|
|
|
|
100
|
if( $special->[0] == T_QUANTIFIER ) { |
432
|
11
|
|
|
|
|
23
|
my $qc = substr $$buffer, 0, 1; |
433
|
|
|
|
|
|
|
|
434
|
11
|
100
|
|
|
|
33
|
if( $qc eq '?' ) { |
435
|
1
|
|
|
|
|
3
|
substr $$buffer, 0, 1, ''; |
436
|
1
|
|
|
|
|
4
|
$special = $pattern_special{$c . $qc}; |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
|
440
|
29
|
|
|
|
|
108
|
$to_return = [ $self->{pos}, T_PATTERN, $c, $special ]; |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
|
444
|
1254
|
100
|
|
|
|
6378
|
if( $to_return ) { |
445
|
36
|
100
|
|
|
|
81
|
if( length $v ) { |
446
|
24
|
|
|
|
|
76
|
$self->unlex( $to_return ); |
447
|
24
|
|
|
|
|
237
|
return [ $self->{pos}, T_STRING, $v, 1 ]; |
448
|
|
|
|
|
|
|
} else { |
449
|
12
|
|
|
|
|
42
|
return $to_return; |
450
|
|
|
|
|
|
|
} |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
|
453
|
1218
|
100
|
66
|
|
|
6053
|
if( $c eq '\\' && $self->quote->{interpolate} ) { |
|
|
100
|
66
|
|
|
|
|
454
|
165
|
|
|
|
|
1420
|
my $qc = substr $$buffer, 0, 1, ''; |
455
|
|
|
|
|
|
|
|
456
|
165
|
50
|
|
|
|
931
|
if( $qc =~ /^[a-zA-Z]$/ ) { |
|
|
0
|
|
|
|
|
|
457
|
165
|
50
|
|
|
|
616
|
if( $quoted_chars{$qc} ) { |
458
|
165
|
|
|
|
|
1050
|
$v .= $quoted_chars{$qc}; |
459
|
|
|
|
|
|
|
} else { |
460
|
0
|
|
|
|
|
0
|
die "Invalid escape '$qc'"; |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
} elsif( $qc =~ /^[0-9]$/ ) { |
463
|
0
|
|
|
|
|
0
|
die "Unsupported numeric escape"; |
464
|
|
|
|
|
|
|
} else { |
465
|
0
|
|
|
|
|
0
|
$v .= $qc; |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
} elsif( $c =~ /^[\$\@]$/ && $self->quote->{interpolate} ) { |
468
|
29
|
50
|
0
|
|
|
306
|
if( $interpolated_pattern |
|
|
100
|
33
|
|
|
|
|
469
|
|
|
|
|
|
|
&& ( !length( $$buffer ) |
470
|
|
|
|
|
|
|
|| index( "()| \r\n\t", |
471
|
|
|
|
|
|
|
substr( $$buffer, 0, 1 ) ) != -1 ) ) { |
472
|
0
|
|
|
|
|
0
|
$v .= $c; |
473
|
|
|
|
|
|
|
} elsif( length $v ) { |
474
|
25
|
|
|
|
|
128
|
$self->unlex( [ $self->{pos}, $ops{$c}, $c ] ); |
475
|
|
|
|
|
|
|
|
476
|
25
|
|
|
|
|
206
|
return [ $self->{pos}, T_STRING, $v ]; |
477
|
|
|
|
|
|
|
} else { |
478
|
4
|
|
|
|
|
25
|
return [ $self->{pos}, $ops{$c}, $c ]; |
479
|
|
|
|
|
|
|
} |
480
|
|
|
|
|
|
|
} else { |
481
|
1024
|
|
|
|
|
2195
|
$v .= $c; |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
|
486
|
0
|
|
|
|
|
0
|
die "Can't get there"; |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
sub lex_alphabetic_identifier { |
490
|
21
|
|
|
21
|
0
|
158
|
my( $self, $flags ) = @_; |
491
|
|
|
|
|
|
|
|
492
|
21
|
50
|
|
|
|
33
|
if( @{$self->tokens} ) { |
|
21
|
|
|
|
|
66
|
|
493
|
0
|
0
|
|
|
|
0
|
return undef if $self->tokens->[-1]->[O_TYPE] != T_ID; |
494
|
0
|
|
|
|
|
0
|
return pop @{$self->tokens}; |
|
0
|
|
|
|
|
0
|
|
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
|
497
|
21
|
|
|
|
|
187
|
local $_ = $self->buffer; |
498
|
|
|
|
|
|
|
|
499
|
21
|
50
|
|
|
|
122
|
if( $flags & LEX_NO_PACKAGE ) { |
500
|
0
|
0
|
|
|
|
0
|
return undef unless $$_ =~ /^[ \t\r\n]*\w/; |
501
|
|
|
|
|
|
|
} else { |
502
|
21
|
100
|
|
|
|
108
|
return undef unless $$_ =~ /^[ \t\r\n]*[':\w]/; |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
|
505
|
17
|
|
|
|
|
67
|
return lex_identifier( $self, $flags ); |
506
|
|
|
|
|
|
|
} |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
sub lex_identifier { |
509
|
342
|
|
|
342
|
0
|
1822
|
my( $self, $flags ) = @_; |
510
|
|
|
|
|
|
|
|
511
|
342
|
50
|
|
|
|
472
|
if( @{$self->tokens} ) { |
|
342
|
|
|
|
|
940
|
|
512
|
0
|
0
|
|
|
|
0
|
return undef if $self->tokens->[-1]->[O_TYPE] != T_ID; |
513
|
0
|
|
|
|
|
0
|
return pop @{$self->tokens}; |
|
0
|
|
|
|
|
0
|
|
514
|
|
|
|
|
|
|
} |
515
|
|
|
|
|
|
|
|
516
|
342
|
|
|
|
|
2314
|
local $_ = $self->buffer; |
517
|
|
|
|
|
|
|
|
518
|
342
|
50
|
33
|
|
|
3221
|
_skip_space( $self ) |
519
|
|
|
|
|
|
|
if defined( $$_ ) && $$_ =~ /^[ \t\r\n]/; |
520
|
|
|
|
|
|
|
|
521
|
342
|
50
|
|
|
|
845
|
return [ $self->{pos}, T_EOF, '' ] unless length $$_; |
522
|
|
|
|
|
|
|
|
523
|
342
|
|
|
|
|
423
|
my $id; |
524
|
342
|
50
|
|
|
|
970
|
$$_ =~ s/^\^([A-Z\[\\\]^_?])//x and do { |
525
|
0
|
|
|
|
|
0
|
$id = [ $self->{pos}, T_ID, chr( ord( $1 ) - ord( 'A' ) + 1 ), T_FQ_ID ]; |
526
|
|
|
|
|
|
|
}; |
527
|
342
|
50
|
33
|
|
|
1188
|
$id or $$_ =~ s/^::(?=\W)//x and do { |
528
|
0
|
|
|
|
|
0
|
$id = [ $self->{pos}, T_ID, 'main::', T_FQ_ID ]; |
529
|
|
|
|
|
|
|
}; |
530
|
342
|
50
|
66
|
|
|
2295
|
$id or $$_ =~ s/^(\'|::)?(\w+)//x and do { |
531
|
341
|
50
|
|
|
|
805
|
if( $flags & LEX_NO_PACKAGE ) { |
532
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_ID, $2, T_ID ]; |
533
|
|
|
|
|
|
|
} |
534
|
|
|
|
|
|
|
|
535
|
341
|
50
|
|
|
|
1352
|
my $ids = defined $1 ? '::' . $2 : $2; |
536
|
341
|
50
|
|
|
|
794
|
my $idt = defined $1 ? T_FQ_ID : T_ID; |
537
|
|
|
|
|
|
|
|
538
|
341
|
|
|
|
|
2300
|
while( $$_ =~ s/^::(\w*)|^\'(\w+)// ) { |
539
|
0
|
0
|
|
|
|
0
|
$ids .= '::' . ( defined $1 ? $1 : $2 ); |
540
|
0
|
|
|
|
|
0
|
$idt = T_FQ_ID; |
541
|
|
|
|
|
|
|
} |
542
|
|
|
|
|
|
|
|
543
|
341
|
|
|
|
|
1311
|
$id = [ $self->{pos}, T_ID, $ids, $idt ]; |
544
|
|
|
|
|
|
|
}; |
545
|
342
|
100
|
33
|
|
|
1180
|
$id or $$_ =~ s/^{\^([A-Z\[\\\]^_?])(\w*)}//x and do { |
546
|
0
|
|
|
|
|
0
|
$id = [ $self->{pos}, T_ID, chr( ord( $1 ) - ord( 'A' ) + 1 ) . $2, T_FQ_ID ]; |
547
|
|
|
|
|
|
|
}; |
548
|
342
|
100
|
33
|
|
|
1992
|
$id or $$_ =~ s/^{//x and do { |
549
|
0
|
|
|
|
|
0
|
my $spcbef = _skip_space( $self ); |
550
|
0
|
|
|
|
|
0
|
my $maybe_id; |
551
|
0
|
0
|
|
|
|
0
|
if( $$_ =~ s/^(\w+)//x ) { |
552
|
0
|
|
|
|
|
0
|
$maybe_id = $1; |
553
|
|
|
|
|
|
|
} else { |
554
|
0
|
|
|
|
|
0
|
$$_ = '{' . $spcbef . $$_; |
555
|
0
|
|
|
|
|
0
|
return undef; |
556
|
|
|
|
|
|
|
} |
557
|
0
|
|
|
|
|
0
|
my $spcaft = _skip_space( $self ); |
558
|
|
|
|
|
|
|
|
559
|
0
|
0
|
|
|
|
0
|
if( $$_ =~ s/^}//x ) { |
|
|
0
|
|
|
|
|
|
560
|
0
|
|
|
|
|
0
|
$id = [ $self->{pos}, T_ID, $maybe_id, T_ID ]; |
561
|
|
|
|
|
|
|
} elsif( $$_ =~ /^\[|^\{/ ) { |
562
|
0
|
|
|
|
|
0
|
++$self->{brackets}; |
563
|
0
|
|
|
|
|
0
|
push @{$self->{pending_brackets}}, $self->{brackets}; |
|
0
|
|
|
|
|
0
|
|
564
|
0
|
|
|
|
|
0
|
$id = [ $self->{pos}, T_ID, $maybe_id, T_ID ]; |
565
|
|
|
|
|
|
|
} else { |
566
|
|
|
|
|
|
|
# not a simple identifier |
567
|
0
|
|
|
|
|
0
|
$$_ = '{' . $spcbef . $maybe_id . $spcaft . $$_; |
568
|
0
|
|
|
|
|
0
|
return undef; |
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
}; |
571
|
342
|
100
|
33
|
|
|
738
|
$id or $$_ =~ /^\$[\${:]/ and do { |
572
|
0
|
|
|
|
|
0
|
return; |
573
|
|
|
|
|
|
|
}; |
574
|
342
|
100
|
33
|
|
|
661
|
$id or $$_ =~ s/^(\W)(?=\W)// and do { |
575
|
0
|
|
|
|
|
0
|
$id = [ $self->{pos}, T_ID, $1, T_FQ_ID ]; |
576
|
|
|
|
|
|
|
}; |
577
|
|
|
|
|
|
|
|
578
|
342
|
100
|
100
|
|
|
1594
|
if( $id && $self->quote && $self->{brackets} == 0 ) { |
|
|
|
66
|
|
|
|
|
579
|
29
|
|
|
|
|
322
|
_quoted_code_lookahead( $self ); |
580
|
|
|
|
|
|
|
} |
581
|
|
|
|
|
|
|
|
582
|
342
|
|
|
|
|
3528
|
return $id; |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
sub lex_number { |
586
|
247
|
|
|
247
|
0
|
417
|
my( $self ) = @_; |
587
|
247
|
|
|
|
|
679
|
local $_ = $self->buffer; |
588
|
247
|
|
|
|
|
1205
|
my( $num, $flags ) = ( '', 0 ); |
589
|
|
|
|
|
|
|
|
590
|
247
|
100
|
|
|
|
879
|
$$_ =~ s/^0([xb]?)//x and do { |
591
|
14
|
50
|
|
|
|
99
|
if( $1 eq 'b' ) { |
|
|
50
|
|
|
|
|
|
592
|
|
|
|
|
|
|
# binary number |
593
|
0
|
0
|
|
|
|
0
|
if( $$_ =~ s/^([01]+)// ) { |
594
|
0
|
|
|
|
|
0
|
$flags = NUM_BINARY; |
595
|
0
|
|
|
|
|
0
|
$num .= $1; |
596
|
|
|
|
|
|
|
|
597
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_NUMBER, $num, $flags ]; |
598
|
|
|
|
|
|
|
} else { |
599
|
0
|
|
|
|
|
0
|
die "Invalid binary digit"; |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
} elsif( $1 eq 'x' ) { |
602
|
|
|
|
|
|
|
# hexadecimal number |
603
|
0
|
0
|
|
|
|
0
|
if( $$_ =~ s/^([0-9a-fA-F]+)// ) { |
604
|
0
|
|
|
|
|
0
|
$flags = NUM_HEXADECIMAL; |
605
|
0
|
|
|
|
|
0
|
$num .= $1; |
606
|
|
|
|
|
|
|
|
607
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_NUMBER, $num, $flags ]; |
608
|
|
|
|
|
|
|
} else { |
609
|
0
|
|
|
|
|
0
|
die "Invalid hexadecimal digit"; |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
} else { |
612
|
|
|
|
|
|
|
# maybe octal number |
613
|
14
|
50
|
|
|
|
61
|
if( $$_ =~ s/^([0-7]+)// ) { |
614
|
0
|
|
|
|
|
0
|
$flags = NUM_OCTAL; |
615
|
0
|
|
|
|
|
0
|
$num .= $1; |
616
|
0
|
0
|
|
|
|
0
|
$$_ =~ /^[89]/ and die "Invalid octal digit"; |
617
|
|
|
|
|
|
|
|
618
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_NUMBER, $num, $flags ]; |
619
|
|
|
|
|
|
|
} else { |
620
|
14
|
|
|
|
|
27
|
$flags = NUM_INTEGER; |
621
|
14
|
|
|
|
|
2000
|
$num = '0' |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
} |
624
|
|
|
|
|
|
|
}; |
625
|
247
|
100
|
|
|
|
1102
|
$$_ =~ s/^(\d+)//x and do { |
626
|
231
|
|
|
|
|
404
|
$flags = NUM_INTEGER; |
627
|
231
|
|
|
|
|
491
|
$num .= $1; |
628
|
|
|
|
|
|
|
}; |
629
|
|
|
|
|
|
|
# '..' operator (es. 12..15) |
630
|
247
|
50
|
|
|
|
876
|
$$_ =~ /^\.\./ and return [ $self->{pos}, T_NUMBER, $num, $flags ]; |
631
|
247
|
100
|
|
|
|
670
|
$$_ =~ s/^\.(\d*)//x and do { |
632
|
2
|
|
|
|
|
5
|
$flags = NUM_FLOAT; |
633
|
2
|
50
|
|
|
|
6
|
$num = '0' unless length $num; |
634
|
2
|
50
|
|
|
|
10
|
$num .= ".$1" if length $1; |
635
|
|
|
|
|
|
|
}; |
636
|
247
|
50
|
|
|
|
720
|
$$_ =~ s/^[eE]([+-]?\d+)//x and do { |
637
|
0
|
|
|
|
|
0
|
$flags = NUM_FLOAT; |
638
|
0
|
|
|
|
|
0
|
$num .= "e$1"; |
639
|
|
|
|
|
|
|
}; |
640
|
|
|
|
|
|
|
|
641
|
247
|
|
|
|
|
1279
|
return [ $self->{pos}, T_NUMBER, $num, $flags ]; |
642
|
|
|
|
|
|
|
} |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
my %quote_end = qw!( ) { } [ ] < >!; |
645
|
|
|
|
|
|
|
my @rx_flags = |
646
|
|
|
|
|
|
|
( FLAG_RX_MULTI_LINE, FLAG_RX_SINGLE_LINE, FLAG_RX_CASE_INSENSITIVE, |
647
|
|
|
|
|
|
|
FLAG_RX_FREE_FORMAT, FLAG_RX_ONCE, FLAG_RX_GLOBAL, FLAG_RX_KEEP, |
648
|
|
|
|
|
|
|
FLAG_RX_EVAL ); |
649
|
|
|
|
|
|
|
my @tr_flags = ( FLAG_RX_COMPLEMENT, FLAG_RX_DELETE, FLAG_RX_SQUEEZE ); |
650
|
|
|
|
|
|
|
my %regex_flags = |
651
|
|
|
|
|
|
|
( m => [ OP_QL_M, 'msixogc', @rx_flags ], |
652
|
|
|
|
|
|
|
qr => [ OP_QL_QR, 'msixo', @rx_flags ], |
653
|
|
|
|
|
|
|
s => [ OP_QL_S, 'msixogce', @rx_flags ], |
654
|
|
|
|
|
|
|
tr => [ OP_QL_TR, 'cds', @tr_flags ], |
655
|
|
|
|
|
|
|
y => [ OP_QL_TR, 'cds', @tr_flags ], |
656
|
|
|
|
|
|
|
); |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
sub _find_end { |
659
|
171
|
|
|
171
|
|
304
|
my( $self, $op, $quote_start ) = @_; |
660
|
|
|
|
|
|
|
|
661
|
171
|
|
|
|
|
477
|
local $_ = $self->buffer; |
662
|
|
|
|
|
|
|
|
663
|
171
|
50
|
33
|
|
|
2281
|
if( $op && !$quote_start ) { |
664
|
0
|
0
|
|
|
|
0
|
if( $$_ =~ /^[ \t\r\n]/ ) { |
665
|
0
|
|
|
|
|
0
|
_skip_space( $self ); |
666
|
|
|
|
|
|
|
} |
667
|
|
|
|
|
|
|
# if we find a fat comma, we got a string constant, not the |
668
|
|
|
|
|
|
|
# start of a quoted string! |
669
|
0
|
0
|
|
|
|
0
|
$$_ =~ /^=>/ and return ( undef, [ $self->{pos}, T_STRING, $op ] ); |
670
|
0
|
0
|
|
|
|
0
|
$$_ =~ s/^([^ \t\r\n])// or die; |
671
|
0
|
|
|
|
|
0
|
$quote_start = $1; |
672
|
|
|
|
|
|
|
} |
673
|
|
|
|
|
|
|
|
674
|
171
|
|
33
|
|
|
833
|
my $quote_end = $quote_end{$quote_start} || $quote_start; |
675
|
171
|
50
|
|
|
|
393
|
my $paired = $quote_start eq $quote_end ? 0 : 1; |
676
|
171
|
|
|
|
|
693
|
my $is_regex = $regex_flags{$op}; |
677
|
171
|
|
|
|
|
296
|
my $pos = $self->{pos}; |
678
|
|
|
|
|
|
|
|
679
|
171
|
|
|
|
|
472
|
my( $interpolated, $delim_count, $str ) = ( 0, 1, '' ); |
680
|
171
|
|
|
|
|
203
|
SCAN_END: for(;;) { |
681
|
171
|
50
|
|
|
|
476
|
$self->_fill_buffer unless length $$_; |
682
|
171
|
50
|
|
|
|
347
|
die "EOF while parsing quoted string" unless length $$_; |
683
|
|
|
|
|
|
|
|
684
|
171
|
|
|
|
|
501
|
while( length $$_ ) { |
685
|
1372
|
|
|
|
|
2066
|
my $c = substr $$_, 0, 1, ''; |
686
|
|
|
|
|
|
|
|
687
|
1372
|
100
|
33
|
|
|
5866
|
if( $c eq '\\' ) { |
|
|
50
|
0
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
688
|
164
|
|
|
|
|
270
|
my $qc = substr $$_, 0, 1, ''; |
689
|
|
|
|
|
|
|
|
690
|
164
|
50
|
33
|
|
|
735
|
if( $qc eq $quote_start || $qc eq $quote_end ) { |
691
|
0
|
|
|
|
|
0
|
$str .= $qc; |
692
|
|
|
|
|
|
|
} else { |
693
|
164
|
|
|
|
|
389
|
$str .= "\\" . $qc; |
694
|
|
|
|
|
|
|
} |
695
|
|
|
|
|
|
|
|
696
|
164
|
|
|
|
|
388
|
next; |
697
|
|
|
|
|
|
|
} elsif( $paired && $c eq $quote_start ) { |
698
|
0
|
|
|
|
|
0
|
++$delim_count; |
699
|
|
|
|
|
|
|
} elsif( $c eq $quote_end ) { |
700
|
171
|
|
|
|
|
492
|
--$delim_count; |
701
|
|
|
|
|
|
|
|
702
|
171
|
50
|
|
|
|
530
|
last SCAN_END unless $delim_count; |
703
|
|
|
|
|
|
|
} elsif( $is_regex |
704
|
|
|
|
|
|
|
&& ( $c eq '$' || $c eq '@' ) |
705
|
|
|
|
|
|
|
&& $quote_start ne "'" ) { |
706
|
0
|
|
|
|
|
0
|
my $nc = substr $$_, 0, 1; |
707
|
|
|
|
|
|
|
|
708
|
0
|
0
|
0
|
|
|
0
|
if( length( $nc ) |
|
|
|
0
|
|
|
|
|
709
|
|
|
|
|
|
|
&& $nc ne $quote_end |
710
|
|
|
|
|
|
|
&& index( "()| \r\n\t", $nc ) == -1 ) { |
711
|
0
|
|
|
|
|
0
|
$interpolated = 1; |
712
|
|
|
|
|
|
|
} |
713
|
|
|
|
|
|
|
} |
714
|
|
|
|
|
|
|
|
715
|
1037
|
|
|
|
|
2291
|
$str .= $c; |
716
|
|
|
|
|
|
|
} |
717
|
|
|
|
|
|
|
} |
718
|
|
|
|
|
|
|
|
719
|
171
|
100
|
|
|
|
864
|
my $interpolate = $op eq 'qq' ? 1 : |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
720
|
|
|
|
|
|
|
$op eq 'q' ? 0 : |
721
|
|
|
|
|
|
|
$op eq 'qw' ? 0 : |
722
|
|
|
|
|
|
|
$quote_start eq "'" ? 0 : |
723
|
|
|
|
|
|
|
1; |
724
|
171
|
50
|
|
|
|
995
|
return ( $quote_start, |
725
|
|
|
|
|
|
|
[ $pos, $is_regex ? T_PATTERN : T_QUOTE, |
726
|
|
|
|
|
|
|
0, $interpolate, \$str, undef, undef, $interpolated ] ); |
727
|
|
|
|
|
|
|
} |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
sub _prepare_sublex { |
730
|
171
|
|
|
171
|
|
483
|
my( $self, $op, $quote_start ) = @_; |
731
|
171
|
|
|
|
|
474
|
my( $quote, $token ) = _find_end( $self, $op, $quote_start ); |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
# oops, found fat comma: not a quote-like operator |
734
|
171
|
50
|
|
|
|
633
|
return $token if $token->[O_TYPE] == T_STRING; |
735
|
|
|
|
|
|
|
|
736
|
171
|
50
|
33
|
|
|
1388
|
if( my $op_descr = $regex_flags{$op} ) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
737
|
|
|
|
|
|
|
# scan second part of substitution/transliteration |
738
|
0
|
0
|
0
|
|
|
0
|
if( $op eq 's' || $op eq 'tr' || $op eq 'y' ) { |
|
|
|
0
|
|
|
|
|
739
|
0
|
0
|
|
|
|
0
|
my $quote_char = $quote_end{$quote} ? undef : $quote; |
740
|
0
|
|
|
|
|
0
|
my( undef, $rest ) = _find_end( $self, $op, $quote_char ); |
741
|
0
|
|
|
|
|
0
|
$token->[O_RX_SECOND_HALF] = $rest; |
742
|
|
|
|
|
|
|
} |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
# scan regexp flags |
745
|
0
|
|
|
|
|
0
|
$token->[O_VALUE] = $op_descr->[0]; |
746
|
0
|
|
|
|
|
0
|
my $fl_str = $op_descr->[1]; |
747
|
0
|
|
|
|
|
0
|
local $_ = $self->buffer; |
748
|
|
|
|
|
|
|
|
749
|
0
|
|
|
|
|
0
|
my $flags = 0; |
750
|
0
|
|
0
|
|
|
0
|
while( length( $$_ ) |
751
|
|
|
|
|
|
|
and ( my $idx = index( $fl_str, substr( $$_, 0, 1 ) ) ) >= 0 ) { |
752
|
0
|
|
|
|
|
0
|
substr $$_, 0, 1, ''; |
753
|
0
|
|
|
|
|
0
|
$flags |= $op_descr->[$idx + 2]; |
754
|
|
|
|
|
|
|
} |
755
|
0
|
|
|
|
|
0
|
$token->[O_RX_FLAGS] = $flags; |
756
|
|
|
|
|
|
|
} elsif( $op eq 'qx' || $op eq "`" ) { |
757
|
0
|
|
|
|
|
0
|
$token->[O_VALUE] = OP_QL_QX; |
758
|
|
|
|
|
|
|
} elsif( $op eq 'qw' ) { |
759
|
0
|
|
|
|
|
0
|
$token->[O_VALUE] = OP_QL_QW; |
760
|
|
|
|
|
|
|
} elsif( $op eq '<' ) { |
761
|
0
|
|
|
|
|
0
|
$token->[O_VALUE] = OP_QL_LT; |
762
|
|
|
|
|
|
|
} |
763
|
|
|
|
|
|
|
|
764
|
171
|
|
|
|
|
559
|
return $token; |
765
|
|
|
|
|
|
|
} |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
sub _prepare_sublex_heredoc { |
768
|
0
|
|
|
0
|
|
0
|
my( $self ) = @_; |
769
|
0
|
|
|
|
|
0
|
my( $quote, $str, $end ) = ( '"', '' ); |
770
|
|
|
|
|
|
|
|
771
|
0
|
|
|
|
|
0
|
local $_ = $self->buffer; |
772
|
0
|
|
|
|
|
0
|
my $pos = $self->{pos}; |
773
|
|
|
|
|
|
|
|
774
|
0
|
0
|
|
|
|
0
|
if( $$_ =~ s/^[ \t]*(['"`])// ) { |
775
|
|
|
|
|
|
|
# << "EOT", << 'EOT', << `EOT` |
776
|
0
|
|
|
|
|
0
|
$quote = $1; |
777
|
|
|
|
|
|
|
|
778
|
0
|
|
|
|
|
0
|
while( $$_ =~ s/^(.*?)(\\)?($quote)// ) { |
779
|
0
|
|
|
|
|
0
|
$end .= $1; |
780
|
0
|
0
|
|
|
|
0
|
if( !$2 ) { |
781
|
0
|
|
|
|
|
0
|
last; |
782
|
|
|
|
|
|
|
} else { |
783
|
0
|
|
|
|
|
0
|
$end .= $quote; |
784
|
|
|
|
|
|
|
} |
785
|
|
|
|
|
|
|
} |
786
|
|
|
|
|
|
|
} else { |
787
|
|
|
|
|
|
|
# <<\EOT, <
|
788
|
0
|
0
|
|
|
|
0
|
if( $$_ =~ s/\\// ) { |
789
|
0
|
|
|
|
|
0
|
$quote = "'"; |
790
|
|
|
|
|
|
|
} |
791
|
|
|
|
|
|
|
|
792
|
0
|
|
|
|
|
0
|
$$_ =~ s/^(\w*)//; |
793
|
0
|
0
|
|
|
|
0
|
warn "Deprecated" unless $1; |
794
|
0
|
|
|
|
|
0
|
$end = $1; |
795
|
|
|
|
|
|
|
} |
796
|
0
|
|
|
|
|
0
|
$end .= "\n"; |
797
|
|
|
|
|
|
|
|
798
|
0
|
|
0
|
|
|
0
|
my $lex = $self->_heredoc_lexer || $self; |
799
|
0
|
|
|
|
|
0
|
my $finished = 0; |
800
|
0
|
0
|
|
|
|
0
|
if( !$lex->stream ) { |
801
|
0
|
|
|
|
|
0
|
$_ = $lex->buffer; |
802
|
0
|
0
|
|
|
|
0
|
if( $$_ =~ s/(.*)^$end//m ) { |
803
|
0
|
|
|
|
|
0
|
$str .= $1; |
804
|
0
|
|
|
|
|
0
|
$finished = 1; |
805
|
|
|
|
|
|
|
} |
806
|
|
|
|
|
|
|
} else { |
807
|
|
|
|
|
|
|
# if the lexer reads from a stream, it buffers at most one line, |
808
|
|
|
|
|
|
|
# so by not using the buffer we skip the rest of the line |
809
|
0
|
|
|
|
|
0
|
my $stream = $lex->stream; |
810
|
0
|
|
|
|
|
0
|
while( defined( my $line = readline $stream ) ) { |
811
|
0
|
0
|
|
|
|
0
|
if( $line eq $end ) { |
812
|
0
|
|
|
|
|
0
|
$finished = 1; |
813
|
0
|
|
|
|
|
0
|
last; |
814
|
|
|
|
|
|
|
} |
815
|
0
|
|
|
|
|
0
|
$str .= $line; |
816
|
|
|
|
|
|
|
} |
817
|
|
|
|
|
|
|
} |
818
|
|
|
|
|
|
|
|
819
|
0
|
0
|
|
|
|
0
|
Carp::confess "EOF while looking for terminator '$end'" unless $finished; |
820
|
|
|
|
|
|
|
|
821
|
0
|
0
|
|
|
|
0
|
return [ $pos, T_QUOTE, $quote eq "`" ? OP_QL_QX : 0, $quote ne "'", \$str ]; |
822
|
|
|
|
|
|
|
} |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
sub lex { |
825
|
6874
|
|
|
6874
|
0
|
25969
|
my( $self, $expect ) = ( @_, X_NOTHING ); |
826
|
|
|
|
|
|
|
|
827
|
6874
|
100
|
|
|
|
7630
|
return pop @{$self->tokens} if @{$self->tokens}; |
|
4700
|
|
|
|
|
27305
|
|
|
6874
|
|
|
|
|
16272
|
|
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
# skip blanks and comments |
830
|
2174
|
|
|
|
|
12211
|
_skip_space( $self ); |
831
|
|
|
|
|
|
|
|
832
|
2174
|
|
|
|
|
5863
|
local $_ = $self->buffer; |
833
|
2174
|
100
|
|
|
|
17446
|
return [ $self->{pos}, T_EOF, '' ] unless length $$_; |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
# numbers |
836
|
2110
|
100
|
|
|
|
11185
|
$$_ =~ /^\d|^\.\d/ and return $self->lex_number; |
837
|
|
|
|
|
|
|
# quote and quote-like operators |
838
|
1863
|
50
|
|
|
|
4859
|
$$_ =~ s/^(q|qq|qx|qw|m|qr|s|tr|y)(?=\W)//x and |
839
|
|
|
|
|
|
|
return _prepare_sublex( $self, $1, undef ); |
840
|
|
|
|
|
|
|
# 'x' operator special case |
841
|
1863
|
50
|
33
|
|
|
4657
|
$$_ =~ /^x[0-9]/ && $expect == X_OPERATOR and do { |
842
|
0
|
|
|
|
|
0
|
$$_ =~ s/^.//; |
843
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_SSTAR, 'x' ]; |
844
|
|
|
|
|
|
|
}; |
845
|
|
|
|
|
|
|
# anything that can start with alphabetic character: package name, |
846
|
|
|
|
|
|
|
# label, identifier, fully qualified identifier, keyword, named |
847
|
|
|
|
|
|
|
# operator |
848
|
1863
|
100
|
|
|
|
6626
|
$$_ =~ s/^(::)?(\w+)//x and do { |
849
|
321
|
|
50
|
|
|
2005
|
my $ids = ( $1 || '' ) . $2; |
850
|
321
|
50
|
|
|
|
927
|
my $fqual = $1 ? 1 : 0; |
851
|
321
|
|
|
|
|
899
|
my $no_space = $$_ !~ /^[ \t\r\n]/; |
852
|
|
|
|
|
|
|
|
853
|
321
|
|
|
|
|
736
|
my $op = $ops{$ids}; |
854
|
321
|
100
|
66
|
|
|
1867
|
my $kw = $op || $fqual ? undef : $Language::P::Keywords::KEYWORDS{$ids}; |
855
|
321
|
100
|
|
|
|
1088
|
my $type = $fqual ? T_FQ_ID : |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
856
|
|
|
|
|
|
|
$op ? -1 : |
857
|
|
|
|
|
|
|
$kw ? $kw : |
858
|
|
|
|
|
|
|
T_ID; |
859
|
|
|
|
|
|
|
|
860
|
321
|
50
|
33
|
|
|
1653
|
if( $no_space && ( $$_ =~ /^::/ |
|
|
|
66
|
|
|
|
|
861
|
|
|
|
|
|
|
|| ( ( $type == T_ID || $type == T_FQ_ID ) |
862
|
|
|
|
|
|
|
&& $$_ =~ /^'\w/ ) ) ) { |
863
|
0
|
|
|
|
|
0
|
while( $$_ =~ s/^::(\w*)|^\'(\w+)// ) { |
864
|
0
|
0
|
|
|
|
0
|
$ids .= '::' . ( defined $1 ? $1 : $2 ); |
865
|
|
|
|
|
|
|
} |
866
|
0
|
0
|
|
|
|
0
|
if( $ids =~ s/::$// ) { |
867
|
|
|
|
|
|
|
# warn for nonexistent package |
868
|
|
|
|
|
|
|
} |
869
|
0
|
|
|
|
|
0
|
$op = undef; |
870
|
0
|
|
|
|
|
0
|
$type = T_FQ_ID; |
871
|
|
|
|
|
|
|
} |
872
|
|
|
|
|
|
|
# force subroutine call |
873
|
321
|
100
|
100
|
|
|
1311
|
if( $no_space && $type == T_ID && $$_ =~ /^\(/ ) { |
|
|
|
100
|
|
|
|
|
874
|
37
|
|
|
|
|
73
|
$type = T_SUB_ID; |
875
|
|
|
|
|
|
|
} |
876
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
# look ahead for fat comma, save the original value for __LINE__ |
878
|
321
|
|
|
|
|
1034
|
my $line = $self->line; |
879
|
321
|
|
|
|
|
1776
|
my $pos = $self->{pos}; |
880
|
321
|
|
|
|
|
624
|
_skip_space( $self ); |
881
|
321
|
50
|
66
|
|
|
9565
|
if( $$_ =~ /^=>/ ) { |
|
|
100
|
100
|
|
|
|
|
882
|
|
|
|
|
|
|
# fully qualified name (foo::moo) is quoted only if not declared |
883
|
0
|
0
|
0
|
|
|
0
|
if( $type == T_FQ_ID |
884
|
|
|
|
|
|
|
&& $self->symbol_table->get_symbol( $ids, '*' ) ) { |
885
|
0
|
|
|
|
|
0
|
return [ $pos, T_ID, $ids, $type ]; |
886
|
|
|
|
|
|
|
} else { |
887
|
0
|
|
|
|
|
0
|
return [ $pos, T_STRING, $ids ]; |
888
|
|
|
|
|
|
|
} |
889
|
|
|
|
|
|
|
} elsif( $expect == X_STATE && $type != T_FQ_ID |
890
|
|
|
|
|
|
|
&& $$_ =~ s/^:(?!:)// ) { |
891
|
7
|
|
|
|
|
38
|
return [ $pos, T_LABEL, $ids ]; |
892
|
|
|
|
|
|
|
} |
893
|
|
|
|
|
|
|
|
894
|
314
|
50
|
66
|
|
|
946
|
if( $type == T_ID && $ids =~ /^__/ ) { |
895
|
0
|
0
|
|
|
|
0
|
if( $ids eq '__FILE__' ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
896
|
0
|
|
|
|
|
0
|
return [ $pos, T_STRING, $self->file ]; |
897
|
|
|
|
|
|
|
} elsif( $ids eq '__LINE__' ) { |
898
|
0
|
|
|
|
|
0
|
return [ $pos, T_NUMBER, $line, NUM_INTEGER ]; |
899
|
|
|
|
|
|
|
} elsif( $ids eq '__PACKAGE__' ) { |
900
|
0
|
|
|
|
|
0
|
return [ $pos, T_PACKAGE, '' ]; |
901
|
|
|
|
|
|
|
} |
902
|
|
|
|
|
|
|
} |
903
|
|
|
|
|
|
|
|
904
|
314
|
100
|
|
|
|
620
|
if( $op ) { |
905
|
|
|
|
|
|
|
# 'x' is an operator only when we expect it |
906
|
2
|
50
|
33
|
|
|
10
|
if( $op == T_SSTAR && $expect != X_OPERATOR ) { |
907
|
0
|
|
|
|
|
0
|
return [ $pos, T_ID, $ids, T_ID ]; |
908
|
|
|
|
|
|
|
} |
909
|
|
|
|
|
|
|
|
910
|
2
|
|
|
|
|
8
|
return [ $pos, $op, $ids ]; |
911
|
|
|
|
|
|
|
} |
912
|
312
|
|
|
|
|
1442
|
return [ $pos, T_ID, $ids, $type ]; |
913
|
|
|
|
|
|
|
}; |
914
|
1542
|
100
|
|
|
|
4583
|
$$_ =~ s/^(["'`])//x and return _prepare_sublex( $self, $1, $1 ); |
915
|
|
|
|
|
|
|
# < when not operator (<> glob, <> file read, << here doc) |
916
|
1371
|
50
|
66
|
|
|
3646
|
$$_ =~ /^ and $expect != X_OPERATOR and do { |
917
|
0
|
|
|
|
|
0
|
$$_ =~ s/^(<<|<)//x; |
918
|
|
|
|
|
|
|
|
919
|
0
|
0
|
|
|
|
0
|
if( $1 eq '<' ) { |
|
|
0
|
|
|
|
|
|
920
|
0
|
|
|
|
|
0
|
return _prepare_sublex( $self, '<', '<' ); |
921
|
|
|
|
|
|
|
} elsif( $1 eq '<<' ) { |
922
|
0
|
|
|
|
|
0
|
return _prepare_sublex_heredoc( $self ); |
923
|
|
|
|
|
|
|
} |
924
|
|
|
|
|
|
|
}; |
925
|
|
|
|
|
|
|
# multi char operators |
926
|
1371
|
100
|
|
|
|
4891
|
$$_ =~ s/^(<=|>=|==|!=|=>|-> |
927
|
|
|
|
|
|
|
|=~|!~ |
928
|
|
|
|
|
|
|
|\.\.|\.\.\. |
929
|
|
|
|
|
|
|
|\+\+|\-\- |
930
|
|
|
|
|
|
|
|\+=|\-=|\*=|\/= |
931
|
|
|
|
|
|
|
|\&\&|\|\|)//x and return [ $self->{pos}, $ops{$1}, $1 ]; |
932
|
1295
|
100
|
|
|
|
3395
|
$$_ =~ s/^\$//x and do { |
933
|
287
|
100
|
|
|
|
758
|
if( $$_ =~ /^\#/ ) { |
934
|
1
|
|
|
|
|
6
|
my $id = $self->lex_identifier( 0 ); |
935
|
|
|
|
|
|
|
|
936
|
1
|
50
|
|
|
|
4
|
if( $id ) { |
937
|
0
|
|
|
|
|
0
|
$self->unlex( $id ); |
938
|
|
|
|
|
|
|
} else { |
939
|
1
|
|
|
|
|
5
|
$$_ =~ s/^\#//x; |
940
|
1
|
|
|
|
|
5
|
return [ $self->{pos}, $ops{'$#'}, '$#' ]; |
941
|
|
|
|
|
|
|
} |
942
|
|
|
|
|
|
|
} |
943
|
286
|
|
|
|
|
1450
|
return [ $self->{pos}, $ops{'$'}, '$' ]; |
944
|
|
|
|
|
|
|
}; |
945
|
|
|
|
|
|
|
# brackets (block, subscripting, anonymous ref constructors) |
946
|
1008
|
100
|
|
|
|
2615
|
$$_ =~ s/^([{}\[\]])// and do { |
947
|
165
|
|
|
|
|
396
|
my $brack = $1; |
948
|
|
|
|
|
|
|
|
949
|
165
|
100
|
100
|
|
|
854
|
if( $brack eq '[' || $brack eq '{' ) { |
950
|
81
|
|
|
|
|
165
|
++$self->{brackets}; |
951
|
|
|
|
|
|
|
} else { |
952
|
84
|
50
|
66
|
|
|
316
|
if( $brack eq '}' |
|
78
|
|
33
|
|
|
602
|
|
953
|
|
|
|
|
|
|
&& @{$self->{pending_brackets}} |
954
|
|
|
|
|
|
|
&& $self->{pending_brackets}[-1] == $self->{brackets} ) { |
955
|
0
|
|
|
|
|
0
|
pop @{$self->{pending_brackets}}; |
|
0
|
|
|
|
|
0
|
|
956
|
0
|
|
|
|
|
0
|
--$self->{brackets}; |
957
|
|
|
|
|
|
|
|
958
|
0
|
|
|
|
|
0
|
return $self->lex( $expect ); |
959
|
|
|
|
|
|
|
} |
960
|
|
|
|
|
|
|
|
961
|
84
|
|
|
|
|
182
|
--$self->{brackets}; |
962
|
|
|
|
|
|
|
|
963
|
84
|
100
|
100
|
|
|
441
|
if( $self->{brackets} == 0 && $self->quote ) { |
964
|
3
|
|
|
|
|
25
|
_quoted_code_lookahead( $self ); |
965
|
|
|
|
|
|
|
} |
966
|
|
|
|
|
|
|
} |
967
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
# disambiguate start of block from anonymous hash |
969
|
165
|
100
|
|
|
|
786
|
if( $brack eq '{' ) { |
970
|
78
|
50
|
|
|
|
386
|
if( $expect == X_TERM ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
971
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_OPHASH, '{' ]; |
972
|
|
|
|
|
|
|
} elsif( $expect == X_OPERATOR ) { |
973
|
|
|
|
|
|
|
# autoquote literal strings in hash subscripts |
974
|
17
|
50
|
|
|
|
74
|
if( $$_ =~ s/^[ \t]*([[:alpha:]_]+)[ \t]*\}// ) { |
975
|
0
|
|
|
|
|
0
|
$self->unlex( [ $self->{pos}, T_CLBRK, '}' ] ); |
976
|
0
|
|
|
|
|
0
|
$self->unlex( [ $self->{pos}, T_STRING, $1 ] ); |
977
|
|
|
|
|
|
|
} |
978
|
|
|
|
|
|
|
} elsif( $expect != X_BLOCK ) { |
979
|
|
|
|
|
|
|
# try to guess if it is a block or anonymous hash |
980
|
11
|
|
|
|
|
48
|
$self->_skip_space; |
981
|
|
|
|
|
|
|
|
982
|
11
|
50
|
|
|
|
43
|
if( $$_ =~ /^}/ ) { |
983
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_OPHASH, '{' ]; |
984
|
|
|
|
|
|
|
} |
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
# treat ' =>', ' ,/=>' lookahead |
987
|
|
|
|
|
|
|
# as indicators of anonymous hash |
988
|
11
|
50
|
|
|
|
93
|
if( $$_ =~ /^([\w"'`])/ ) { |
989
|
11
|
|
|
|
|
33
|
my $first = $1; |
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
# can only be a string literal, quote like operator |
992
|
|
|
|
|
|
|
# or identifier |
993
|
11
|
|
|
|
|
59
|
my $next = $self->peek( X_NOTHING ); |
994
|
|
|
|
|
|
|
|
995
|
11
|
|
|
|
|
39
|
$self->_skip_space; |
996
|
11
|
50
|
33
|
|
|
106
|
if( $$_ =~ /^=>/ |
|
|
|
33
|
|
|
|
|
997
|
|
|
|
|
|
|
|| ( $$_ =~ /^,/ && $next->[O_TYPE] != T_ID ) ) { |
998
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_OPHASH, '{' ]; |
999
|
|
|
|
|
|
|
} |
1000
|
|
|
|
|
|
|
} |
1001
|
|
|
|
|
|
|
} |
1002
|
|
|
|
|
|
|
} |
1003
|
|
|
|
|
|
|
|
1004
|
165
|
|
|
|
|
837
|
return [ $self->{pos}, $ops{$brack}, $brack ]; |
1005
|
|
|
|
|
|
|
}; |
1006
|
|
|
|
|
|
|
# / (either regex start or division operator) |
1007
|
843
|
50
|
|
|
|
1904
|
$$_ =~ s/^\///x and do { |
1008
|
0
|
0
|
0
|
|
|
0
|
if( $expect == X_TERM || $expect == X_STATE ) { |
1009
|
0
|
|
|
|
|
0
|
return _prepare_sublex( $self, 'm', '/' ); |
1010
|
|
|
|
|
|
|
} else { |
1011
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_SLASH, '/' ]; |
1012
|
|
|
|
|
|
|
} |
1013
|
|
|
|
|
|
|
}; |
1014
|
|
|
|
|
|
|
# filetest operators |
1015
|
843
|
50
|
|
|
|
9927
|
$$_ =~ s/^-([rwxoRWXOezsfdlpSugkbctTBMMAC])(?=\W)// and do { |
1016
|
0
|
|
|
|
|
0
|
my $op = $1; |
1017
|
0
|
0
|
|
|
|
0
|
if( $$_ =~ /^[ \t]*=>/ ) { |
1018
|
0
|
|
|
|
|
0
|
$self->unlex( [ 'STRING', $1 ] ); |
1019
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_MINUS, '-' ]; |
1020
|
|
|
|
|
|
|
} |
1021
|
|
|
|
|
|
|
|
1022
|
0
|
|
|
|
|
0
|
return [ $self->{pos}, T_FILETEST, $op, $filetest{$op} ]; |
1023
|
|
|
|
|
|
|
}; |
1024
|
|
|
|
|
|
|
# single char operators |
1025
|
843
|
50
|
|
|
|
7076
|
$$_ =~ s/^([:;,()\?<>!~=\/\\\+\-\.\|^\*%@&])//x and return [ $self->{pos}, $ops{$1}, $1 ]; |
1026
|
|
|
|
|
|
|
|
1027
|
0
|
|
|
|
|
0
|
die "Lexer error: '$$_'"; |
1028
|
|
|
|
|
|
|
} |
1029
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
sub _fill_buffer { |
1031
|
615
|
|
|
615
|
|
835
|
my( $self ) = @_; |
1032
|
615
|
|
|
|
|
1834
|
my $stream = $self->stream; |
1033
|
615
|
50
|
|
|
|
3322
|
return unless $stream; |
1034
|
615
|
|
|
|
|
1526
|
my $buffer = $self->buffer; |
1035
|
615
|
|
|
|
|
3980
|
my $l = readline $stream; |
1036
|
|
|
|
|
|
|
|
1037
|
615
|
100
|
|
|
|
1637
|
if( defined $l ) { |
1038
|
551
|
|
|
|
|
1474
|
$$buffer .= $l; |
1039
|
|
|
|
|
|
|
} |
1040
|
|
|
|
|
|
|
} |
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
1; |