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