line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Pinwheel::View::ERB; |
2
|
|
|
|
|
|
|
|
3
|
10
|
|
|
10
|
|
74203
|
use strict; |
|
10
|
|
|
|
|
22
|
|
|
10
|
|
|
|
|
575
|
|
4
|
10
|
|
|
10
|
|
60
|
use warnings; |
|
10
|
|
|
|
|
25
|
|
|
10
|
|
|
|
|
444
|
|
5
|
|
|
|
|
|
|
|
6
|
10
|
|
|
10
|
|
60
|
use Carp; |
|
10
|
|
|
|
|
21
|
|
|
10
|
|
|
|
|
1129
|
|
7
|
10
|
|
|
10
|
|
8679
|
use Exporter; |
|
10
|
|
|
|
|
24
|
|
|
10
|
|
|
|
|
558
|
|
8
|
|
|
|
|
|
|
|
9
|
10
|
|
|
10
|
|
2980
|
use Pinwheel::View::String; |
|
10
|
|
|
|
|
28
|
|
|
10
|
|
|
|
|
478
|
|
10
|
10
|
|
|
10
|
|
25360
|
use Pinwheel::View::Wrap; |
|
10
|
|
|
|
|
29
|
|
|
10
|
|
|
|
|
2675
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
13
|
|
|
|
|
|
|
our @EXPORT_OK = qw(parse_template); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our $OPEN_TAG_RE = qr{ |
17
|
|
|
|
|
|
|
(.*?) |
18
|
|
|
|
|
|
|
<%(=?) |
19
|
|
|
|
|
|
|
}x; |
20
|
|
|
|
|
|
|
our $CLOSE_TAG_RE = qr{ |
21
|
|
|
|
|
|
|
\s* |
22
|
|
|
|
|
|
|
((?: |
23
|
|
|
|
|
|
|
(?:(['"])(?:\\.|[^\2])*?\2) |
24
|
|
|
|
|
|
|
| (?:\#.*?(?=-?%>)) |
25
|
|
|
|
|
|
|
| [^'"] |
26
|
|
|
|
|
|
|
)*?) |
27
|
|
|
|
|
|
|
\s* |
28
|
|
|
|
|
|
|
(-?)%> |
29
|
|
|
|
|
|
|
}x; |
30
|
|
|
|
|
|
|
our $TEXT = 1; |
31
|
|
|
|
|
|
|
our $CODE = 2; |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
our $slow_attrs; |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
BEGIN { |
36
|
10
|
|
|
10
|
|
35
|
my ($pkg, %attrs, $s); |
37
|
|
|
|
|
|
|
|
38
|
10
|
|
|
|
|
37
|
$pkg = \%Pinwheel::View::Wrap::; |
39
|
10
|
|
|
|
|
318
|
foreach (keys %$pkg) { |
40
|
50
|
|
|
|
|
84
|
map { $attrs{$_} = 1 } @{$pkg->{$_}{'WRAP_METHODS'}}; |
|
114
|
|
|
|
|
222
|
|
|
50
|
|
|
|
|
481
|
|
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
10
|
|
|
|
|
118
|
$s = '(?:' . join('|', keys %attrs) . ')'; |
44
|
10
|
|
|
|
|
55631
|
$slow_attrs = qr/^${s}$/; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub parse_template |
49
|
|
|
|
|
|
|
{ |
50
|
111
|
|
|
111
|
1
|
46475
|
my ($s, $name) = @_; |
51
|
111
|
|
|
|
|
205
|
my ($writer, $lineno, $line, $addnl); |
52
|
|
|
|
|
|
|
|
53
|
111
|
100
|
|
|
|
376
|
$name = 'anonymous' if (!$name); |
54
|
111
|
|
|
|
|
662
|
$writer = code_writer($name); |
55
|
111
|
|
|
|
|
331
|
$addnl = 0; |
56
|
111
|
|
|
|
|
1135
|
foreach $line (split(/\r?\n/, $s)) { |
57
|
252
|
|
|
|
|
637
|
$lineno++; |
58
|
252
|
|
|
|
|
618
|
$addnl = parse_template_line($line, $lineno, $writer, $addnl); |
59
|
|
|
|
|
|
|
} |
60
|
99
|
100
|
100
|
|
|
2889
|
if ($addnl && $s =~ /\n\s*$/) { |
61
|
53
|
|
|
|
|
389
|
$writer->{echo_raw}('"\n"'); |
62
|
|
|
|
|
|
|
} |
63
|
99
|
|
|
|
|
282
|
return compile($writer->{eof}(), $name); |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub parse_template_line |
67
|
|
|
|
|
|
|
{ |
68
|
252
|
|
|
252
|
0
|
564
|
my ($line, $lineno, $writer, $addnl) = @_; |
69
|
252
|
|
|
|
|
583
|
my ($linetype, @parts, $echo); |
70
|
2
|
|
|
|
|
18
|
my ($text, $type, $data); |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# Collect the parts (text and code) and classify the line: |
73
|
|
|
|
|
|
|
# bit 0: contains non-whitespace text |
74
|
|
|
|
|
|
|
# bit 1: contains code which outputs something, ie <%= ... %> |
75
|
|
|
|
|
|
|
# bit 2: contains code which does not output anything, ie <% ... %> |
76
|
252
|
|
|
|
|
422
|
$linetype = 0; |
77
|
252
|
|
|
|
|
3643
|
while ($line =~ /\G$OPEN_TAG_RE/gc) { |
78
|
124
|
|
|
|
|
419
|
$echo = ($2 eq '='); |
79
|
124
|
100
|
|
|
|
393
|
if ($1 ne '') { |
80
|
55
|
|
|
|
|
527
|
push @parts, [$TEXT, $1]; |
81
|
55
|
100
|
|
|
|
455
|
$linetype |= 1 if ($1 !~ /^\s*$/); |
82
|
|
|
|
|
|
|
} |
83
|
124
|
100
|
|
|
|
3384
|
$line =~ /\G$CLOSE_TAG_RE/gc || |
84
|
|
|
|
|
|
|
$writer->{error}("Missing %>", $lineno); |
85
|
123
|
100
|
|
|
|
1233
|
if ($1 !~ /^\s*$/) { |
86
|
121
|
|
|
|
|
714
|
push @parts, [$CODE, $1, $echo]; |
87
|
121
|
100
|
|
|
|
988
|
$linetype |= $echo ? 2 : 4; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
} |
90
|
251
|
100
|
|
|
|
1290
|
if ($line =~ /\G(.*[^\s])\s*$/) { |
91
|
129
|
|
|
|
|
442
|
push @parts, [$TEXT, $1]; |
92
|
129
|
|
|
|
|
225
|
$linetype |= 1; |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# If the line contains code, supply the line number for error messages |
96
|
|
|
|
|
|
|
# (both compile time and runtime) |
97
|
251
|
100
|
|
|
|
1164
|
$writer->{line}($lineno) if ($linetype & 6); |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# Write this line of the template |
100
|
251
|
100
|
|
|
|
1082
|
$text = $addnl ? "\n" : ''; |
101
|
251
|
|
|
|
|
667
|
push @parts, [-1, undef]; |
102
|
251
|
|
|
|
|
509
|
do { |
103
|
539
|
|
|
|
|
657
|
($type, $data, $echo) = @{shift(@parts)}; |
|
539
|
|
|
|
|
1993
|
|
104
|
539
|
100
|
100
|
|
|
15779
|
if ($type != $TEXT && $text ne '') { |
105
|
226
|
|
|
|
|
761
|
$writer->{echo_raw}($writer->{string}($text)); |
106
|
226
|
|
|
|
|
392
|
$text = ''; |
107
|
|
|
|
|
|
|
} |
108
|
539
|
100
|
100
|
|
|
2491
|
$text .= $data if ($type == $TEXT && $linetype != 4); |
109
|
539
|
100
|
|
|
|
2469
|
parse_code(lexer($data), $writer, $echo) if ($type == $CODE); |
110
|
|
|
|
|
|
|
} while ($type != -1); |
111
|
|
|
|
|
|
|
|
112
|
240
|
|
|
|
|
1189
|
return ($linetype != 4); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub code_writer |
117
|
|
|
|
|
|
|
{ |
118
|
380
|
|
|
380
|
0
|
44111
|
my $name = shift; |
119
|
380
|
|
|
|
|
615
|
my ($strings, %stridx, %functions); |
120
|
2
|
|
|
|
|
5
|
my ($code, @blocks, $lineno); |
121
|
|
|
|
|
|
|
|
122
|
380
|
|
|
|
|
10008
|
$strings = []; |
123
|
380
|
|
|
|
|
838
|
$code = ''; |
124
|
380
|
|
|
|
|
574
|
$lineno = '?'; |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
return { |
127
|
|
|
|
|
|
|
open => sub { |
128
|
84
|
|
|
84
|
|
323
|
push @blocks, [$_[0], $_[1], $lineno]; |
129
|
|
|
|
|
|
|
}, |
130
|
|
|
|
|
|
|
need => sub { |
131
|
31
|
100
|
100
|
31
|
|
229
|
_error("Unexpected '$_[1]'", $lineno, $name) |
132
|
|
|
|
|
|
|
if (scalar(@blocks) < 1 || $blocks[-1][0] ne $_[0]); |
133
|
|
|
|
|
|
|
}, |
134
|
|
|
|
|
|
|
close => sub { |
135
|
57
|
|
|
57
|
|
340
|
my $block = pop(@blocks); |
136
|
57
|
100
|
|
|
|
144
|
_error("Unexpected 'end'", $lineno, $name) unless $block; |
137
|
55
|
|
|
|
|
163
|
return $block->[1]; |
138
|
|
|
|
|
|
|
}, |
139
|
|
|
|
|
|
|
eof => sub { |
140
|
215
|
100
|
|
215
|
|
1775
|
_error("Unclosed '$blocks[-1][0]'", $blocks[-1][2], $name) |
141
|
|
|
|
|
|
|
if (scalar(@blocks) > 0); |
142
|
212
|
|
|
|
|
652
|
my @fnlist = keys(%functions); |
143
|
212
|
|
|
|
|
962
|
return ($code, $strings, \@fnlist); |
144
|
|
|
|
|
|
|
}, |
145
|
|
|
|
|
|
|
string => sub { |
146
|
312
|
100
|
|
312
|
|
1388
|
if (!exists($stridx{$_[0]})) { |
147
|
285
|
|
|
|
|
2295
|
$stridx{$_[0]} = push(@$strings, $_[0]) - 1; |
148
|
|
|
|
|
|
|
} |
149
|
312
|
|
|
|
|
2591
|
return '$strings->[' . $stridx{$_[0]} . ']'; |
150
|
|
|
|
|
|
|
}, |
151
|
|
|
|
|
|
|
error => sub { |
152
|
55
|
100
|
|
55
|
|
549
|
_error($_[0], $_[1] ? $_[1] : $lineno, $name); |
153
|
|
|
|
|
|
|
}, |
154
|
|
|
|
|
|
|
function => sub { |
155
|
95
|
|
|
95
|
|
280
|
$functions{$_[0]} = 1; |
156
|
|
|
|
|
|
|
}, |
157
|
|
|
|
|
|
|
echo => sub { |
158
|
202
|
|
|
202
|
|
621
|
$code .= "\$r .= $_[0];\n"; |
159
|
|
|
|
|
|
|
}, |
160
|
|
|
|
|
|
|
echo_raw => sub { |
161
|
277
|
|
|
277
|
|
1133
|
$code .= "\$r->concat_raw($_[0]);\n"; |
162
|
|
|
|
|
|
|
}, |
163
|
|
|
|
|
|
|
do => sub { |
164
|
256
|
|
|
256
|
|
885
|
$code .= "$_[0];\n"; |
165
|
|
|
|
|
|
|
}, |
166
|
|
|
|
|
|
|
line => sub { |
167
|
115
|
|
|
115
|
|
214
|
$lineno = $_[0]; |
168
|
115
|
|
|
|
|
623
|
$code .= "\$lineno = $_[0];\n"; |
169
|
|
|
|
|
|
|
} |
170
|
380
|
|
|
|
|
23041
|
}; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# ============================================================================== |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub parse_code |
178
|
|
|
|
|
|
|
{ |
179
|
515
|
|
|
516
|
0
|
1508
|
my ($lexer, $writer, $echo) = @_; |
180
|
515
|
|
|
|
|
769
|
my ($left, $conditional, $type, $next_type); |
181
|
|
|
|
|
|
|
|
182
|
515
|
|
|
|
|
1453
|
$type = $lexer->(1)[0]; |
183
|
515
|
|
|
|
|
1153
|
$next_type = $lexer->(2)[0]; |
184
|
515
|
100
|
100
|
|
|
4849
|
if ($type eq '') { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
|
|
|
|
|
185
|
12
|
100
|
|
|
|
139
|
$writer->{error}('Invalid syntax') if ($lexer->(1)[1] ne ''); |
186
|
8
|
|
|
|
|
22
|
$left = ''; |
187
|
|
|
|
|
|
|
} elsif ($type eq 'STMT') { |
188
|
157
|
|
|
|
|
340
|
$left = parse_statement($lexer, $writer); |
189
|
142
|
|
|
|
|
643
|
$writer->{do}($left); |
190
|
|
|
|
|
|
|
} elsif (($type eq 'ID' || $type eq '@ID') && $next_type eq '=') { |
191
|
17
|
|
|
|
|
60
|
$left = parse_assign($lexer, $writer); |
192
|
16
|
|
|
|
|
48
|
$writer->{do}($left); |
193
|
|
|
|
|
|
|
} elsif ($type eq 'ID' && $next_type eq ',') { |
194
|
8
|
|
|
|
|
140
|
$left = parse_unpack($lexer, $writer); |
195
|
6
|
|
|
|
|
28
|
$writer->{do}($left); |
196
|
|
|
|
|
|
|
} else { |
197
|
325
|
|
|
|
|
825
|
$left = parse_expr($lexer, $writer); |
198
|
294
|
|
100
|
|
|
887
|
$conditional = parse_conditional($lexer, $writer) || ''; |
199
|
294
|
100
|
|
|
|
1252
|
$writer->{$echo ? 'echo' : 'do'}($left . $conditional); |
200
|
|
|
|
|
|
|
} |
201
|
462
|
100
|
|
|
|
976
|
$writer->{error}('Invalid syntax') if ($lexer->(1)[0] ne ''); |
202
|
457
|
|
|
|
|
9492
|
return $left; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
sub parse_statement |
207
|
|
|
|
|
|
|
{ |
208
|
157
|
|
|
158
|
0
|
236
|
my ($lexer, $writer) = @_; |
209
|
157
|
|
|
|
|
184
|
my ($left, $token, $stmt, $expr); |
210
|
|
|
|
|
|
|
|
211
|
157
|
|
|
|
|
511
|
$token = $lexer->(1); |
212
|
157
|
|
|
|
|
430
|
$stmt = $token->[1]; |
213
|
157
|
100
|
|
|
|
643
|
if ($stmt eq 'for') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
214
|
20
|
|
|
|
|
149
|
$left = parse_for($lexer, $writer); |
215
|
|
|
|
|
|
|
} elsif ($stmt eq 'if') { |
216
|
54
|
|
|
|
|
168
|
$writer->{open}('if', '}'); |
217
|
54
|
|
|
|
|
128
|
$lexer->(); # Absorb 'if' |
218
|
54
|
|
|
|
|
270
|
$expr = parse_test_expr($lexer, $writer); |
219
|
54
|
|
|
|
|
166
|
$left = "if ($expr) {"; |
220
|
|
|
|
|
|
|
} elsif ($stmt eq 'elsif') { |
221
|
7
|
|
|
|
|
27
|
$writer->{need}('if', 'elsif'); |
222
|
5
|
|
|
|
|
119
|
$lexer->(); # Absorb 'elsif' |
223
|
5
|
|
|
|
|
21
|
$expr = parse_test_expr($lexer, $writer); |
224
|
5
|
|
|
|
|
14
|
$left = "} elsif ($expr) {"; |
225
|
|
|
|
|
|
|
} elsif ($stmt eq 'else') { |
226
|
24
|
|
|
|
|
174
|
$writer->{need}('if', 'else'); |
227
|
22
|
|
|
|
|
54
|
$lexer->(); # Absorb 'else' |
228
|
22
|
|
|
|
|
39
|
$left = "} else {"; |
229
|
|
|
|
|
|
|
} else { # elsif ($stmt eq 'end') { |
230
|
56
|
|
|
|
|
224
|
$lexer->(); # Absorb 'end' |
231
|
56
|
|
|
|
|
191
|
$left = $writer->{close}(); |
232
|
|
|
|
|
|
|
} |
233
|
142
|
|
|
|
|
430
|
return $left; |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub parse_conditional |
237
|
|
|
|
|
|
|
{ |
238
|
294
|
|
|
295
|
0
|
605
|
my ($lexer, $writer) = @_; |
239
|
294
|
|
|
|
|
425
|
my ($expr, $token); |
240
|
|
|
|
|
|
|
|
241
|
294
|
|
|
|
|
581
|
$token = $lexer->(1); |
242
|
294
|
100
|
100
|
|
|
2513
|
return if ($token->[0] ne 'STMT' || $token->[1] ne 'if'); |
243
|
|
|
|
|
|
|
|
244
|
3
|
|
|
|
|
15
|
$lexer->(); # Absorb 'if' |
245
|
3
|
|
|
|
|
8
|
$expr = parse_test_expr($lexer, $writer); |
246
|
3
|
|
|
|
|
128
|
return " if ($expr)"; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub parse_for |
250
|
|
|
|
|
|
|
{ |
251
|
20
|
|
|
21
|
0
|
40
|
my ($lexer, $writer) = @_; |
252
|
20
|
|
|
|
|
27
|
my ($left, $token, @vars); |
253
|
|
|
|
|
|
|
|
254
|
20
|
|
|
|
|
136
|
$lexer->(); # Absorb 'for' |
255
|
20
|
|
|
|
|
72
|
$writer->{open}('for', '}'); |
256
|
20
|
|
|
|
|
31
|
do { |
257
|
24
|
|
|
|
|
256
|
$token = $lexer->(); |
258
|
24
|
100
|
|
|
|
86
|
$writer->{error}('Expected variable') unless ($token->[0] eq 'ID'); |
259
|
20
|
|
|
|
|
44
|
push @vars, $token->[1]; |
260
|
20
|
|
|
|
|
138
|
$token = $lexer->(); |
261
|
|
|
|
|
|
|
} while ($token->[0] eq ','); |
262
|
16
|
100
|
|
|
|
61
|
$writer->{error}("Expected 'in'") unless ($token->[0] eq 'in'); |
263
|
|
|
|
|
|
|
|
264
|
12
|
|
|
|
|
34
|
$left = 'foreach (@{' . parse_expr($lexer, $writer) . '}) '; |
265
|
11
|
100
|
|
|
|
142
|
if (scalar(@vars) == 1) { |
266
|
9
|
|
|
|
|
241
|
$left .= '{ $locals->{\'' . $vars[0] . '\'} = $_;'; |
267
|
|
|
|
|
|
|
} else { |
268
|
3
|
|
|
|
|
16
|
$left .= '{ @$locals{qw(' . join(' ', @vars) . ')} = @$_;'; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
11
|
|
|
|
|
227
|
return $left; |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
sub parse_test_expr |
275
|
|
|
|
|
|
|
{ |
276
|
77
|
|
|
78
|
0
|
155
|
my ($lexer, $writer) = @_; |
277
|
77
|
|
|
|
|
132
|
my ($left, $right, $token); |
278
|
|
|
|
|
|
|
|
279
|
77
|
|
|
|
|
309
|
$left = parse_test_cmp($lexer, $writer); |
280
|
76
|
|
|
|
|
198
|
while ($token = $lexer->(1)) { |
281
|
86
|
100
|
100
|
|
|
465
|
last if ($token->[0] ne 'or' && $token->[0] ne 'and'); |
282
|
11
|
|
|
|
|
152
|
$lexer->(); # Absorb 'or'/'and' |
283
|
11
|
|
|
|
|
31
|
$right = parse_test_cmp($lexer, $writer); |
284
|
11
|
100
|
|
|
|
33
|
if ($token->[0] eq 'or') { |
285
|
7
|
|
|
|
|
111
|
$left = "($left || $right)"; |
286
|
|
|
|
|
|
|
} else { |
287
|
5
|
|
|
|
|
26
|
$left = "($left && $right)"; |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
} |
290
|
76
|
|
|
|
|
197
|
return $left; |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
sub parse_test_cmp |
294
|
|
|
|
|
|
|
{ |
295
|
87
|
|
|
88
|
0
|
211
|
my ($lexer, $writer) = @_; |
296
|
87
|
|
|
|
|
119
|
my ($left, $right, $token, $cmp); |
297
|
|
|
|
|
|
|
|
298
|
87
|
|
|
|
|
236
|
$left = parse_expr($lexer, $writer); |
299
|
86
|
|
|
|
|
303
|
while ($token = $lexer->(1)) { |
300
|
107
|
|
|
|
|
208
|
$cmp = $token->[0]; |
301
|
107
|
100
|
|
|
|
385
|
last unless ($cmp =~ /^==|!=|<=|>=|<|>$/); |
302
|
22
|
|
|
|
|
174
|
$lexer->(); # Absorb comparison operator |
303
|
22
|
|
|
|
|
59
|
$right = parse_expr($lexer, $writer); |
304
|
22
|
100
|
|
|
|
85
|
if ($cmp eq '==') { |
|
|
100
|
|
|
|
|
|
305
|
8
|
|
|
|
|
251
|
$left = "($left eq $right)"; |
306
|
|
|
|
|
|
|
} elsif ($cmp eq '!=') { |
307
|
5
|
|
|
|
|
25
|
$left = "($left ne $right)"; |
308
|
|
|
|
|
|
|
} else { |
309
|
11
|
|
|
|
|
40
|
$left = "($left $cmp $right)"; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
} |
312
|
86
|
|
|
|
|
468
|
return $left; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
sub parse_assign |
317
|
|
|
|
|
|
|
{ |
318
|
17
|
|
|
18
|
0
|
35
|
my ($lexer, $writer) = @_; |
319
|
17
|
|
|
|
|
22
|
my ($right, $ns, $token); |
320
|
|
|
|
|
|
|
|
321
|
17
|
|
|
|
|
159
|
$token = $lexer->(); |
322
|
17
|
100
|
|
|
|
61
|
$ns = ($token->[0] eq 'ID') ? "\$locals->" : "\$globals->"; |
323
|
17
|
|
|
|
|
32
|
$lexer->(); # Absorb '=' |
324
|
17
|
|
|
|
|
244
|
$right = parse_expr($lexer, $writer); |
325
|
16
|
|
|
|
|
83
|
return "$ns\{'$token->[1]'\} = $right"; |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
sub parse_unpack |
329
|
|
|
|
|
|
|
{ |
330
|
8
|
|
|
9
|
0
|
24
|
my ($lexer, $writer) = @_; |
331
|
8
|
|
|
|
|
100
|
my ($left, $right, $token, @vars); |
332
|
|
|
|
|
|
|
|
333
|
8
|
|
|
|
|
19
|
do { |
334
|
17
|
|
|
|
|
30
|
$token = $lexer->(); |
335
|
17
|
100
|
|
|
|
151
|
$writer->{error}('Expected variable') unless ($token->[0] eq 'ID'); |
336
|
16
|
|
|
|
|
58
|
push @vars, $token->[1]; |
337
|
16
|
|
|
|
|
31
|
$token = $lexer->(); |
338
|
|
|
|
|
|
|
} while ($token->[0] eq ','); |
339
|
7
|
100
|
|
|
|
189
|
$writer->{error}("Expected '='") unless ($token->[0] eq '='); |
340
|
|
|
|
|
|
|
|
341
|
6
|
|
|
|
|
29
|
$left = '@$locals{qw(' . join(' ', @vars) . ')}'; |
342
|
6
|
|
|
|
|
20
|
$right = parse_expr($lexer, $writer); |
343
|
6
|
|
|
|
|
150
|
return $left . ' = @{' . $right . '}'; |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
sub parse_expr |
348
|
|
|
|
|
|
|
{ |
349
|
565
|
|
|
566
|
0
|
837
|
my ($lexer, $writer) = @_; |
350
|
565
|
|
|
|
|
708
|
my ($left, $right, $token); |
351
|
|
|
|
|
|
|
|
352
|
565
|
|
|
|
|
1415
|
$left = parse_product($lexer, $writer); |
353
|
530
|
|
|
|
|
1092
|
while ($token = $lexer->(1)) { |
354
|
585
|
100
|
100
|
|
|
3017
|
last if ($token->[0] ne '+' && $token->[0] ne '-'); |
355
|
59
|
|
|
|
|
256
|
$lexer->(); # Absorb '+' or '-' |
356
|
59
|
|
|
|
|
127
|
$right = parse_product($lexer, $writer); |
357
|
56
|
100
|
|
|
|
142
|
if ($token->[0] eq '+') { |
358
|
43
|
|
|
|
|
291
|
$left = "_add($left, $right)"; |
359
|
|
|
|
|
|
|
} else { |
360
|
14
|
|
|
|
|
56
|
$left = "($left - $right)"; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
} |
363
|
527
|
|
|
|
|
1335
|
return $left; |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
sub parse_product |
367
|
|
|
|
|
|
|
{ |
368
|
623
|
|
|
623
|
0
|
1183
|
my ($lexer, $writer) = @_; |
369
|
623
|
|
|
|
|
711
|
my ($left, $right, $token, $op); |
370
|
|
|
|
|
|
|
|
371
|
623
|
|
|
|
|
1269
|
$left = parse_neg($lexer, $writer); |
372
|
585
|
|
|
|
|
1299
|
while ($token = $lexer->(1)) { |
373
|
603
|
|
|
|
|
1228
|
$op = $token->[0]; |
374
|
603
|
100
|
100
|
|
|
4627
|
last if ($op ne '*' && $op ne '/' && $op ne '%'); |
|
|
|
100
|
|
|
|
|
375
|
19
|
|
|
|
|
222
|
$lexer->(); # Absorb '*', '/', or '%' |
376
|
19
|
|
|
|
|
47
|
$right = parse_neg($lexer, $writer); |
377
|
19
|
|
|
|
|
66
|
$left = "($left $op $right)"; |
378
|
|
|
|
|
|
|
} |
379
|
585
|
|
|
|
|
1515
|
return $left; |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
sub parse_neg |
383
|
|
|
|
|
|
|
{ |
384
|
641
|
|
|
641
|
0
|
764
|
my ($lexer, $writer) = @_; |
385
|
641
|
|
|
|
|
691
|
my ($left, $token); |
386
|
|
|
|
|
|
|
|
387
|
641
|
|
|
|
|
1295
|
$token = $lexer->(1); |
388
|
641
|
100
|
|
|
|
2480
|
if ($token->[0] eq '') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
389
|
5
|
|
|
|
|
15
|
$writer->{error}('Missing or invalid expression'); |
390
|
|
|
|
|
|
|
} elsif ($token->[0] eq '!') { |
391
|
20
|
|
|
|
|
153
|
my ($n, $fn); |
392
|
20
|
|
|
|
|
37
|
do { $lexer->(); $n++; } while ($lexer->(1)[0] eq '!'); |
|
25
|
|
|
|
|
48
|
|
|
25
|
|
|
|
|
307
|
|
393
|
20
|
100
|
|
|
|
64
|
$left = ($n & 1) ? '!' : '!!'; |
394
|
20
|
|
|
|
|
52
|
$left .= "(" . parse_atom($lexer, $writer) . ')'; |
395
|
|
|
|
|
|
|
} elsif ($token->[0] eq '-') { |
396
|
11
|
|
|
|
|
128
|
$lexer->(); # Absorb '-' |
397
|
11
|
|
|
|
|
30
|
$left = '-' . parse_atom($lexer, $writer); |
398
|
|
|
|
|
|
|
} else { |
399
|
608
|
|
|
|
|
1189
|
$left = parse_atom($lexer, $writer); |
400
|
|
|
|
|
|
|
} |
401
|
603
|
|
|
|
|
1771
|
return $left; |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
sub parse_atom |
405
|
|
|
|
|
|
|
{ |
406
|
637
|
|
|
637
|
0
|
3167
|
my ($lexer, $writer) = @_; |
407
|
637
|
|
|
|
|
977
|
my ($left, $token); |
408
|
|
|
|
|
|
|
|
409
|
637
|
|
|
|
|
1306
|
$token = $lexer->(1); |
410
|
637
|
100
|
100
|
|
|
3765
|
if ($token->[0] eq 'NUM') { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
411
|
293
|
|
|
|
|
454
|
$left = $lexer->()->[1]; |
412
|
|
|
|
|
|
|
} elsif ($token->[0] eq 'STR') { |
413
|
79
|
|
|
|
|
303
|
$left = $writer->{string}($lexer->()->[1]); |
414
|
|
|
|
|
|
|
} elsif ($token->[0] eq 'SYM') { |
415
|
9
|
|
|
|
|
22
|
$left = $writer->{string}($lexer->()->[1]); |
416
|
|
|
|
|
|
|
} elsif ($token->[0] eq '(') { |
417
|
18
|
|
|
|
|
108
|
$lexer->(); # Absorb '(' |
418
|
18
|
|
|
|
|
167
|
$left = parse_test_expr($lexer, $writer); |
419
|
17
|
|
|
|
|
41
|
$token = $lexer->(); |
420
|
17
|
100
|
|
|
|
53
|
$writer->{error}('Missing )') unless ($token->[0] eq ')'); |
421
|
|
|
|
|
|
|
} elsif ($token->[0] eq '{') { |
422
|
12
|
|
|
|
|
130
|
$left = parse_hash($lexer, $writer); |
423
|
|
|
|
|
|
|
} elsif ($token->[0] eq '[') { |
424
|
9
|
|
|
|
|
25
|
$left = parse_array($lexer, $writer); |
425
|
|
|
|
|
|
|
} elsif ($token->[0] eq 'ID' && $lexer->(2)[0] eq '(') { |
426
|
94
|
|
|
|
|
270
|
$left = parse_call($lexer, $writer); |
427
|
|
|
|
|
|
|
} elsif ($token->[0] eq 'ID' || $token->[0] eq '@ID') { |
428
|
124
|
|
|
|
|
422
|
$left = parse_attr($lexer, $writer); |
429
|
|
|
|
|
|
|
} else { |
430
|
7
|
|
|
|
|
30
|
$writer->{error}('Missing or invalid expression'); |
431
|
|
|
|
|
|
|
} |
432
|
603
|
|
|
|
|
1785
|
return $left; |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub parse_array |
436
|
|
|
|
|
|
|
{ |
437
|
9
|
|
|
9
|
0
|
109
|
my ($lexer, $writer) = @_; |
438
|
9
|
|
|
|
|
16
|
my ($left, $token); |
439
|
|
|
|
|
|
|
|
440
|
9
|
|
|
|
|
11
|
$left = '['; |
441
|
9
|
|
|
|
|
119
|
$token = $lexer->(); # Absorb '[' |
442
|
9
|
|
|
|
|
20
|
$token = $lexer->(1); |
443
|
9
|
|
|
|
|
21
|
while ($token->[0] ne ']') { |
444
|
13
|
|
|
|
|
129
|
$left .= parse_expr($lexer, $writer) . ', '; |
445
|
12
|
|
|
|
|
28
|
$token = $lexer->(1); |
446
|
12
|
100
|
|
|
|
30
|
last if ($token->[0] ne ','); |
447
|
6
|
|
|
|
|
101
|
$token = $lexer->(); |
448
|
|
|
|
|
|
|
} |
449
|
8
|
|
|
|
|
17
|
$token = $lexer->(); # Absorb ']' |
450
|
8
|
100
|
|
|
|
18
|
$writer->{error}('Missing ]') if ($token->[0] ne ']'); |
451
|
7
|
|
|
|
|
122
|
return $left . ']'; |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
sub parse_hash |
455
|
|
|
|
|
|
|
{ |
456
|
12
|
|
|
12
|
0
|
23
|
my ($lexer, $writer) = @_; |
457
|
12
|
|
|
|
|
15
|
my ($left, $token); |
458
|
|
|
|
|
|
|
|
459
|
12
|
|
|
|
|
120
|
$left = '{'; |
460
|
12
|
|
|
|
|
40
|
$token = $lexer->(); # Absorb '{' |
461
|
12
|
|
|
|
|
23
|
$token = $lexer->(); |
462
|
12
|
|
|
|
|
138
|
while ($token->[0] ne '}') { |
463
|
12
|
100
|
|
|
|
37
|
$writer->{error}('Expected key') if ($token->[0] ne 'SYM'); |
464
|
11
|
|
|
|
|
26
|
$left .= "'$token->[1]' => "; |
465
|
11
|
|
|
|
|
128
|
$token = $lexer->(); |
466
|
11
|
100
|
|
|
|
49
|
$writer->{error}("Expected '=>'") if ($token->[0] ne '=>'); |
467
|
10
|
|
|
|
|
26
|
$left .= parse_expr($lexer, $writer) . ', '; |
468
|
10
|
|
|
|
|
136
|
$token = $lexer->(); |
469
|
10
|
100
|
|
|
|
39
|
last if ($token->[0] ne ','); |
470
|
3
|
|
|
|
|
11
|
$token = $lexer->(); |
471
|
|
|
|
|
|
|
} |
472
|
10
|
100
|
|
|
|
155
|
$writer->{error}('Missing }') if ($token->[0] ne '}'); |
473
|
9
|
|
|
|
|
39
|
return $left . '}'; |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
sub parse_call |
477
|
|
|
|
|
|
|
{ |
478
|
94
|
|
|
94
|
0
|
151
|
my ($lexer, $writer) = @_; |
479
|
94
|
|
|
|
|
260
|
my ($left, $fn, $token, @params); |
480
|
|
|
|
|
|
|
|
481
|
94
|
|
|
|
|
217
|
$fn = $lexer->()->[1]; |
482
|
94
|
|
|
|
|
278
|
$writer->{function}($fn); |
483
|
94
|
|
|
|
|
710
|
$lexer->(); # Absorb '(' |
484
|
|
|
|
|
|
|
|
485
|
94
|
|
|
|
|
213
|
$token = $lexer->(1); |
486
|
94
|
100
|
|
|
|
249
|
if ($token->[0] ne ')') { |
487
|
56
|
|
|
|
|
836
|
do { |
488
|
69
|
100
|
100
|
|
|
145
|
if ($lexer->(1)[0] eq 'SYM' && $lexer->(2)[0] eq '=>') { |
489
|
13
|
|
|
|
|
32
|
push @params, "'" . $lexer->()->[1] . "'"; |
490
|
13
|
|
|
|
|
661
|
$lexer->(); # Absorb '=>' |
491
|
|
|
|
|
|
|
} |
492
|
69
|
|
|
|
|
187
|
push @params, parse_expr($lexer, $writer); |
493
|
66
|
|
|
|
|
213
|
$token = $lexer->(); |
494
|
|
|
|
|
|
|
} while ($token->[0] eq ','); |
495
|
|
|
|
|
|
|
} else { |
496
|
39
|
|
|
|
|
213
|
$lexer->(); # Absorb ')' |
497
|
|
|
|
|
|
|
} |
498
|
91
|
100
|
|
|
|
268
|
$writer->{error}('Missing )') if ($token->[0] ne ')'); |
499
|
|
|
|
|
|
|
|
500
|
85
|
100
|
|
|
|
267
|
if ($lexer->(1)[0] eq 'do') { |
501
|
13
|
|
|
|
|
129
|
$lexer->(); # Absorb 'do' |
502
|
13
|
100
|
|
|
|
37
|
$writer->{error}('Invalid syntax') if ($lexer->(1)[0] ne ''); |
503
|
11
|
|
|
|
|
28
|
push @params, "sub { my \$r = \$r->clone([])"; |
504
|
11
|
|
|
|
|
235
|
$writer->{open}('do', '$r->to_string(); })'); |
505
|
11
|
|
|
|
|
54
|
$left = "\$fns->{'$fn'}->(" . join(', ', @params); |
506
|
|
|
|
|
|
|
} else { |
507
|
73
|
|
|
|
|
364
|
$left = "\$fns->{'$fn'}->(" . join(', ', @params) . ')'; |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
|
510
|
83
|
|
|
|
|
1032
|
return $left; |
511
|
|
|
|
|
|
|
} |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
sub parse_attr |
514
|
|
|
|
|
|
|
{ |
515
|
124
|
|
|
124
|
0
|
194
|
my ($lexer, $writer) = @_; |
516
|
124
|
|
|
|
|
152
|
my ($left, $token, @attribs, $ns, $fn, $s); |
517
|
|
|
|
|
|
|
|
518
|
124
|
|
|
|
|
418
|
$token = $lexer->(); |
519
|
124
|
100
|
|
|
|
366
|
$ns = ($token->[0] eq 'ID') ? "\$locals->" : "\$globals->"; |
520
|
124
|
|
|
|
|
330
|
$left = "$ns\{'$token->[1]'\}"; |
521
|
124
|
|
|
|
|
310
|
$fn = '_getattr'; |
522
|
124
|
|
|
|
|
232
|
$s = $lexer->(1)[0]; |
523
|
124
|
|
100
|
|
|
594
|
while ($s eq '.' || $s eq '[') { |
524
|
65
|
|
|
|
|
237
|
$lexer->(); # Absorb '.' |
525
|
65
|
100
|
|
|
|
148
|
if ($s eq '.') { |
526
|
53
|
|
|
|
|
89
|
$token = $lexer->(); |
527
|
53
|
100
|
100
|
|
|
394
|
$writer->{error}('Missing attribute') |
528
|
|
|
|
|
|
|
if ($token->[0] ne 'ID' && $token->[0] ne 'STMT'); |
529
|
46
|
100
|
|
|
|
374
|
$fn = '_getattr_slow' if ($token->[1] =~ $slow_attrs); |
530
|
46
|
|
|
|
|
213
|
push @attribs, "'$token->[1]'"; |
531
|
|
|
|
|
|
|
} else { |
532
|
13
|
|
|
|
|
149
|
push @attribs, parse_expr($lexer, $writer); |
533
|
13
|
|
|
|
|
34
|
$token = $lexer->(); |
534
|
13
|
100
|
|
|
|
44
|
$writer->{error}("Expected ']'") if ($token->[0] ne ']'); |
535
|
|
|
|
|
|
|
} |
536
|
57
|
|
|
|
|
452
|
$s = $lexer->(1)[0]; |
537
|
|
|
|
|
|
|
} |
538
|
116
|
100
|
|
|
|
348
|
if (scalar(@attribs) > 0) { |
539
|
43
|
|
|
|
|
169
|
$left = "$fn($left, " . join(', ', @attribs) . ')'; |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
116
|
|
|
|
|
620
|
return $left; |
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
# ============================================================================== |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
sub _add |
550
|
|
|
|
|
|
|
{ |
551
|
23
|
100
|
|
23
|
|
104
|
return $_[0]->add($_[1]) if ref($_[0]); |
552
|
22
|
100
|
|
|
|
78
|
return $_[1]->radd($_[0]) if ref($_[1]); |
553
|
21
|
100
|
100
|
|
|
483
|
return $_[0] + $_[1] if ($_[0] =~ /^-?\d+$/ && $_[1] =~ /^-?\d+$/); |
554
|
6
|
|
|
|
|
116
|
return $_[0] . $_[1]; |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
sub _getattr |
558
|
|
|
|
|
|
|
{ |
559
|
16
|
|
|
16
|
|
39
|
my $obj = shift; |
560
|
16
|
100
|
|
|
|
374
|
$obj = ((ref($obj) eq 'HASH') ? $obj->{$_} : $obj->$_) foreach (@_); |
561
|
14
|
|
|
|
|
113
|
return $obj; |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
sub _getattr_slow |
565
|
|
|
|
|
|
|
{ |
566
|
21
|
|
|
21
|
|
51
|
my $obj = shift; |
567
|
|
|
|
|
|
|
|
568
|
21
|
|
|
|
|
130
|
foreach (@_) { |
569
|
30
|
100
|
|
|
|
241
|
$obj = ref($obj) ? ( |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
570
|
|
|
|
|
|
|
ref($obj) eq 'ARRAY' ? $Pinwheel::View::Wrap::array->$_($obj) : ( |
571
|
|
|
|
|
|
|
ref($obj) eq 'HASH' ? $obj->{$_} : $obj->$_ |
572
|
|
|
|
|
|
|
) |
573
|
|
|
|
|
|
|
) : $Pinwheel::View::Wrap::scalar->$_($obj); |
574
|
|
|
|
|
|
|
} |
575
|
|
|
|
|
|
|
|
576
|
19
|
|
|
|
|
154
|
return $obj; |
577
|
|
|
|
|
|
|
} |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
sub _error |
580
|
|
|
|
|
|
|
{ |
581
|
69
|
|
|
69
|
|
241
|
my ($msg, $lineno, $name) = @_; |
582
|
69
|
|
|
|
|
2135
|
die "$msg in '$name' at line $lineno\n"; |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
sub compile |
587
|
|
|
|
|
|
|
{ |
588
|
211
|
|
|
211
|
0
|
601
|
my ($code, $strings, $fns, $name) = @_; |
589
|
211
|
|
|
|
|
408
|
my $checkfns; |
590
|
211
|
100
|
|
|
|
628
|
$name = 'anonymous' if (!$name); |
591
|
211
|
|
|
|
|
356
|
$checkfns = ''; |
592
|
211
|
|
|
|
|
966
|
foreach (@$fns) { |
593
|
50
|
|
|
|
|
265
|
$checkfns .= |
594
|
|
|
|
|
|
|
"die \"Unknown function '$_' in '$name'\"" . |
595
|
|
|
|
|
|
|
" unless exists(\$fns->{'$_'});\n"; |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
return eval <
|
598
|
|
|
|
|
|
|
sub { |
599
|
|
|
|
|
|
|
my (\$locals, \$globals, \$fns) = \@_; |
600
|
|
|
|
|
|
|
my (\$r, \$lineno); |
601
|
|
|
|
|
|
|
\$r = Pinwheel::View::String->new('', \\&_escape); |
602
|
|
|
|
|
|
|
\$lineno = 0; |
603
|
|
|
|
|
|
|
$checkfns |
604
|
|
|
|
|
|
|
eval { |
605
|
|
|
|
|
|
|
local \$SIG{__WARN__} = sub { |
606
|
|
|
|
|
|
|
chomp(my \$msg = shift); |
607
|
|
|
|
|
|
|
die "\$msg at \$name line \$lineno"; |
608
|
|
|
|
|
|
|
}; |
609
|
|
|
|
|
|
|
no warnings qw(uninitialized); |
610
|
|
|
|
|
|
|
$code |
611
|
|
|
|
|
|
|
1 |
612
|
|
|
|
|
|
|
}; |
613
|
|
|
|
|
|
|
_error(\$@, \$lineno, \$name) if (\$@); |
614
|
|
|
|
|
|
|
return \$r; |
615
|
|
|
|
|
|
|
} |
616
|
|
|
|
|
|
|
EOF |
617
|
5
|
|
|
5
|
|
261
|
} |
|
5
|
|
|
5
|
|
19
|
|
|
5
|
|
|
5
|
|
822
|
|
|
5
|
|
|
5
|
|
248
|
|
|
5
|
|
|
5
|
|
24
|
|
|
5
|
|
|
5
|
|
514
|
|
|
5
|
|
|
1
|
|
369
|
|
|
5
|
|
|
1
|
|
23
|
|
|
5
|
|
|
1
|
|
684
|
|
|
5
|
|
|
1
|
|
254
|
|
|
5
|
|
|
1
|
|
21
|
|
|
5
|
|
|
1
|
|
789
|
|
|
5
|
|
|
1
|
|
251
|
|
|
5
|
|
|
1
|
|
29
|
|
|
5
|
|
|
1
|
|
856
|
|
|
5
|
|
|
1
|
|
268
|
|
|
5
|
|
|
1
|
|
25
|
|
|
5
|
|
|
1
|
|
448
|
|
|
211
|
|
|
1
|
|
107272
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
142
|
|
|
1
|
|
|
1
|
|
10
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
144
|
|
|
1
|
|
|
1
|
|
10
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
155
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
1
|
|
812
|
|
|
1
|
|
|
1
|
|
57
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
166
|
|
|
1
|
|
|
1
|
|
9
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
125
|
|
|
1
|
|
|
1
|
|
6
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
133
|
|
|
1
|
|
|
1
|
|
9
|
|
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
1
|
|
153
|
|
|
1
|
|
|
1
|
|
6
|
|
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
1
|
|
119
|
|
|
1
|
|
|
1
|
|
7
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
113
|
|
|
1
|
|
|
1
|
|
10
|
|
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
1
|
|
127
|
|
|
1
|
|
|
1
|
|
9
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
261
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
1
|
|
167
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
9
|
|
|
1
|
|
|
1
|
|
128
|
|
|
1
|
|
|
1
|
|
17
|
|
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
1
|
|
116
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
121
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
115
|
|
|
1
|
|
|
1
|
|
7
|
|
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
1
|
|
114
|
|
|
1
|
|
|
1
|
|
10
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
152
|
|
|
1
|
|
|
1
|
|
11
|
|
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
1
|
|
151
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
144
|
|
|
1
|
|
|
1
|
|
10
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
121
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
1
|
|
|
|
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
sub _escape |
620
|
|
|
|
|
|
|
{ |
621
|
184
|
|
|
184
|
|
406
|
my ($s) = @_; |
622
|
184
|
100
|
|
|
|
505
|
return unless defined($s); |
623
|
181
|
100
|
|
|
|
1963
|
return $s unless ($s =~ /[&<>'"\x80-\xff]/); |
624
|
7
|
|
|
|
|
100
|
$s =~ s/&/&/g; |
625
|
7
|
|
|
|
|
26
|
$s =~ s/
|
626
|
7
|
|
|
|
|
20
|
$s =~ s/>/>/g; |
627
|
7
|
|
|
|
|
131
|
$s =~ s/'/'/g; |
628
|
7
|
|
|
|
|
19
|
$s =~ s/\"/"/g; |
629
|
7
|
|
|
|
|
24
|
$s =~ s/([\xc0-\xef][\x80-\xbf]+)/_make_utf8_entity($1)/ge; |
|
3
|
|
|
|
|
120
|
|
630
|
7
|
|
|
|
|
42
|
return $s; |
631
|
|
|
|
|
|
|
} |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
sub _make_utf8_entity |
634
|
|
|
|
|
|
|
{ |
635
|
3
|
|
|
3
|
|
14
|
my ($i, @bytes) = split(//, shift()); |
636
|
3
|
100
|
|
|
|
407
|
$i = ord($i) & ((ord($i) < 0xe0) ? 0x1f : 0x0f); |
637
|
3
|
|
|
|
|
20
|
$i = ($i << 6) + (ord($_) & 0x3f) foreach @bytes; |
638
|
3
|
|
|
|
|
13
|
return "&#$i;"; |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
# ============================================================================== |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
sub lexer |
646
|
|
|
|
|
|
|
{ |
647
|
565
|
|
|
565
|
0
|
57111
|
my $s = shift; |
648
|
565
|
|
|
|
|
856
|
my @buf; |
649
|
|
|
|
|
|
|
my $lexer = sub { |
650
|
2091
|
|
|
2091
|
|
2526
|
while (1) { |
651
|
2590
|
100
|
|
|
|
9237
|
return ['STMT', $1] if $s =~ /\G(if|elsif|else|for|end)(?!\w)/gcx; |
652
|
2425
|
100
|
|
|
|
25240
|
return [',', ''] if $s =~ /\G,/gc; |
653
|
2385
|
100
|
|
|
|
5320
|
return ['=>', ''] if $s =~ /\G=>/gc; |
654
|
2362
|
100
|
|
|
|
5218
|
return ['.', ''] if $s =~ /\G\./gc; |
655
|
2307
|
100
|
|
|
|
7089
|
return [$1, ''] if $s =~ /\G(==|!=|<=|>=|[-=+*\/%<>!]|[{}])/gc; |
656
|
2116
|
100
|
|
|
|
5071
|
return ['do', ''] if $s =~ /\Gdo(?!\w)/gc; |
657
|
2102
|
100
|
|
|
|
4479
|
return ['in', ''] if $s =~ /\Gin(?!\w)/gc; |
658
|
2089
|
100
|
|
|
|
5543
|
return ['or', ''] if $s =~ /\G(\|\||or(?!\w))/gc; |
659
|
2081
|
100
|
|
|
|
4590
|
return ['and', ''] if $s =~ /\G(\&\&|and(?!\w))/gc; |
660
|
2075
|
100
|
|
|
|
4773
|
return ['(', ''] if $s =~ /\G\(/gc; |
661
|
1959
|
100
|
|
|
|
4386
|
return [')', ''] if $s =~ /\G\)/gc; |
662
|
1856
|
100
|
|
|
|
4407
|
return ['[', ''] if $s =~ /\G\[/gc; |
663
|
1836
|
100
|
|
|
|
3906
|
return [']', ''] if $s =~ /\G\]/gc; |
664
|
1819
|
100
|
|
|
|
6940
|
return ['NUM', $1] if $s =~ /\G(\d+)/gc; |
665
|
1501
|
100
|
|
|
|
4745
|
return ['STR', $2] if $s =~ /\G(['"])(.*?)\1/gc; |
666
|
1420
|
100
|
|
|
|
5465
|
return ['ID', $1] if $s =~ /\G([A-Za-z_]\w*)/gc; |
667
|
1107
|
100
|
|
|
|
2614
|
return ['@ID', $1] if $s =~ /\G@([A-Za-z_]\w*)/gc; |
668
|
1081
|
100
|
|
|
|
2413
|
return ['SYM', $1] if $s =~ /\G:([A-Za-z_]\w*)/gc; |
669
|
1047
|
100
|
|
|
|
3291
|
last if $s !~ /\G(?:\s+|#.*)/gc; |
670
|
|
|
|
|
|
|
} |
671
|
548
|
|
|
|
|
1732
|
$s =~ /\G(.*)/; |
672
|
548
|
|
|
|
|
3389
|
return ['', $1]; |
673
|
565
|
|
|
|
|
2280
|
}; |
674
|
|
|
|
|
|
|
return sub { |
675
|
6890
|
100
|
|
6890
|
|
13720
|
if ($_[0]) { |
676
|
5300
|
|
|
|
|
6930
|
my $n = shift; |
677
|
5300
|
|
|
|
|
14668
|
push @buf, &$lexer() while (@buf < $n); |
678
|
5300
|
|
|
|
|
17137
|
return $buf[$n - 1]; |
679
|
|
|
|
|
|
|
} else { |
680
|
1591
|
100
|
|
|
|
5224
|
return shift(@buf) if (@buf > 0); |
681
|
245
|
|
|
|
|
550
|
return &$lexer(); |
682
|
|
|
|
|
|
|
} |
683
|
565
|
|
|
|
|
11435
|
}; |
684
|
|
|
|
|
|
|
} |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
1; |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
__DATA__ |