line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Text::Handlebars::Compiler; |
2
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:DOY'; |
3
|
|
|
|
|
|
|
$Text::Handlebars::Compiler::VERSION = '0.05'; |
4
|
12
|
|
|
12
|
|
382188
|
use Mouse; |
|
12
|
|
|
|
|
28
|
|
|
12
|
|
|
|
|
102
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
extends 'Text::Xslate::Compiler'; |
7
|
|
|
|
|
|
|
|
8
|
12
|
|
|
12
|
|
4291
|
use Try::Tiny; |
|
12
|
|
|
|
|
24
|
|
|
12
|
|
|
|
|
35207
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
has '+syntax' => ( |
11
|
|
|
|
|
|
|
default => 'Handlebars', |
12
|
|
|
|
|
|
|
); |
13
|
|
|
|
|
|
|
|
14
|
162
|
|
|
162
|
0
|
749
|
sub define_helper { shift->parser->define_helper(@_) } |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
sub _generate_block_body { |
17
|
70
|
|
|
70
|
|
15341
|
my $self = shift; |
18
|
70
|
|
|
|
|
100
|
my ($node) = @_; |
19
|
|
|
|
|
|
|
|
20
|
70
|
|
|
|
|
103
|
my @compiled = map { $self->compile_ast($_) } @{ $node->second }; |
|
70
|
|
|
|
|
198
|
|
|
70
|
|
|
|
|
192
|
|
21
|
|
|
|
|
|
|
|
22
|
70
|
100
|
|
|
|
14653
|
unshift @compiled, $self->_localize_vars($node->first) |
23
|
|
|
|
|
|
|
if $node->first; |
24
|
|
|
|
|
|
|
|
25
|
70
|
|
|
|
|
3349
|
return @compiled; |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub _generate_key { |
29
|
685
|
|
|
685
|
|
125171
|
my $self = shift; |
30
|
685
|
|
|
|
|
945
|
my ($node) = @_; |
31
|
|
|
|
|
|
|
|
32
|
685
|
|
|
|
|
1873
|
my $var = $node->clone(arity => 'variable'); |
33
|
|
|
|
|
|
|
|
34
|
685
|
|
|
|
|
15272
|
return $self->compile_ast($self->check_lambda($var)); |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub _generate_key_field { |
38
|
66
|
|
|
66
|
|
15416
|
my $self = shift; |
39
|
66
|
|
|
|
|
98
|
my ($node) = @_; |
40
|
|
|
|
|
|
|
|
41
|
66
|
|
|
|
|
191
|
my $field = $node->clone(arity => 'field'); |
42
|
|
|
|
|
|
|
|
43
|
66
|
|
|
|
|
1474
|
return $self->compile_ast($self->check_lambda($field)); |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub _generate_call { |
47
|
1683
|
|
|
1683
|
|
59587
|
my $self = shift; |
48
|
1683
|
|
|
|
|
2441
|
my ($node) = @_; |
49
|
|
|
|
|
|
|
|
50
|
1683
|
100
|
|
|
|
4943
|
if ($node->is_helper) { |
51
|
42
|
|
|
|
|
142
|
my @args; |
52
|
|
|
|
|
|
|
my @hash; |
53
|
42
|
|
|
|
|
65
|
for my $arg (@{ $node->second }) { |
|
42
|
|
|
|
|
130
|
|
54
|
43
|
100
|
|
|
|
138
|
if ($arg->arity eq 'pair') { |
55
|
4
|
|
|
|
|
21
|
push @hash, $arg->first, $arg->second; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
else { |
58
|
39
|
|
|
|
|
101
|
push @args, $arg; |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
42
|
|
|
|
|
140
|
my $hash = $self->make_hash(@hash); |
63
|
|
|
|
|
|
|
|
64
|
42
|
|
|
|
|
1338
|
unshift @args, $self->vars; |
65
|
|
|
|
|
|
|
|
66
|
42
|
100
|
|
|
|
1296
|
if ($node->is_block_helper) { |
67
|
34
|
|
|
|
|
49
|
push @{ $node->first->second }, $hash; |
|
34
|
|
|
|
|
142
|
|
68
|
34
|
|
|
|
|
135
|
$node->second(\@args); |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
else { |
71
|
8
|
|
|
|
|
35
|
$node->second([ @args, $hash ]); |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
1683
|
|
|
|
|
4476
|
return $self->SUPER::_generate_call($node); |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub _generate_partial { |
79
|
3
|
|
|
3
|
|
237
|
my $self = shift; |
80
|
3
|
|
|
|
|
7
|
my ($node) = @_; |
81
|
|
|
|
|
|
|
|
82
|
3
|
|
|
|
|
10
|
my $file = $node->first; |
83
|
3
|
50
|
|
|
|
12
|
if (ref($file) eq 'ARRAY') { |
84
|
3
|
|
|
|
|
14
|
$file = $node->clone( |
85
|
|
|
|
|
|
|
arity => 'binary', |
86
|
|
|
|
|
|
|
id => '~', |
87
|
|
|
|
|
|
|
first => $file->[0], |
88
|
|
|
|
|
|
|
second => $node->clone(arity => 'suffix'), |
89
|
|
|
|
|
|
|
); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
3
|
|
|
|
|
144
|
my $args = $node->second; |
93
|
3
|
100
|
|
|
|
76
|
if ($args) { |
94
|
1
|
|
|
|
|
4
|
$args = [ $self->new_vars($args) ]; |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
return ( |
98
|
3
|
|
|
|
|
73
|
$self->compile_ast( |
99
|
|
|
|
|
|
|
$self->make_ternary( |
100
|
|
|
|
|
|
|
$self->find_file($file->clone), |
101
|
|
|
|
|
|
|
$node->clone( |
102
|
|
|
|
|
|
|
arity => 'include', |
103
|
|
|
|
|
|
|
id => 'include', |
104
|
|
|
|
|
|
|
first => $file->clone, |
105
|
|
|
|
|
|
|
second => $args, |
106
|
|
|
|
|
|
|
), |
107
|
|
|
|
|
|
|
$self->literal(''), |
108
|
|
|
|
|
|
|
), |
109
|
|
|
|
|
|
|
), |
110
|
|
|
|
|
|
|
); |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub _generate_suffix { |
114
|
6
|
|
|
6
|
|
545
|
my $self = shift; |
115
|
6
|
|
|
|
|
11
|
my ($node) = @_; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
return ( |
118
|
6
|
|
|
|
|
17
|
$self->opcode('suffix'), |
119
|
|
|
|
|
|
|
); |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub find_file { |
123
|
3
|
|
|
3
|
0
|
61
|
my $self = shift; |
124
|
3
|
|
|
|
|
7
|
my ($filename) = @_; |
125
|
|
|
|
|
|
|
|
126
|
3
|
|
|
|
|
13
|
return $filename->clone( |
127
|
|
|
|
|
|
|
arity => 'unary', |
128
|
|
|
|
|
|
|
id => 'find_file', |
129
|
|
|
|
|
|
|
first => $filename, |
130
|
|
|
|
|
|
|
); |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub _generate_for { |
134
|
35
|
|
|
35
|
|
13926
|
my $self = shift; |
135
|
35
|
|
|
|
|
63
|
my ($node) = @_; |
136
|
|
|
|
|
|
|
|
137
|
35
|
|
|
|
|
156
|
my @opcodes = $self->SUPER::_generate_for(@_); |
138
|
|
|
|
|
|
|
return ( |
139
|
35
|
|
|
|
|
36338
|
@opcodes, |
140
|
|
|
|
|
|
|
$self->opcode('nil'), |
141
|
|
|
|
|
|
|
); |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
sub _generate_block { |
145
|
69
|
|
|
69
|
|
11027
|
my $self = shift; |
146
|
69
|
|
|
|
|
176
|
my ($node) = @_; |
147
|
|
|
|
|
|
|
|
148
|
69
|
|
|
|
|
187
|
my $name = $node->first; |
149
|
69
|
|
|
|
|
111
|
my %block = %{ $node->second }; |
|
69
|
|
|
|
|
311
|
|
150
|
|
|
|
|
|
|
|
151
|
69
|
100
|
|
|
|
284
|
if ($name->arity eq 'call') { |
152
|
|
|
|
|
|
|
return $self->compile_ast( |
153
|
|
|
|
|
|
|
$name->clone( |
154
|
|
|
|
|
|
|
first => $self->call( |
155
|
|
|
|
|
|
|
$node, |
156
|
|
|
|
|
|
|
'(make_block_helper)', |
157
|
|
|
|
|
|
|
$self->vars, |
158
|
|
|
|
|
|
|
$name->first, |
159
|
|
|
|
|
|
|
$block{if}{raw_text}->clone, |
160
|
|
|
|
|
|
|
($block{else} |
161
|
|
|
|
|
|
|
? $block{else}{raw_text}->clone |
162
|
34
|
100
|
|
|
|
102
|
: $self->literal('')), |
163
|
|
|
|
|
|
|
), |
164
|
|
|
|
|
|
|
is_block_helper => 1, |
165
|
|
|
|
|
|
|
), |
166
|
|
|
|
|
|
|
); |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
35
|
|
|
|
|
114
|
my $iterations = $self->make_ternary( |
170
|
|
|
|
|
|
|
$self->is_falsy($name->clone), |
171
|
|
|
|
|
|
|
$self->make_array($self->literal(1)), |
172
|
|
|
|
|
|
|
$self->make_ternary( |
173
|
|
|
|
|
|
|
$self->is_array_ref($name->clone), |
174
|
|
|
|
|
|
|
$name->clone, |
175
|
|
|
|
|
|
|
$self->make_array($self->literal(1)), |
176
|
|
|
|
|
|
|
), |
177
|
|
|
|
|
|
|
); |
178
|
|
|
|
|
|
|
|
179
|
35
|
|
|
|
|
1328
|
my $loop_var = $self->parser->symbol('(loop_var)')->clone(arity => 'variable'); |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
my $body_block = [ |
182
|
|
|
|
|
|
|
$self->make_ternary( |
183
|
|
|
|
|
|
|
$self->is_falsy($name->clone), |
184
|
|
|
|
|
|
|
$name->clone( |
185
|
|
|
|
|
|
|
arity => 'block_body', |
186
|
|
|
|
|
|
|
first => undef, |
187
|
|
|
|
|
|
|
second => [ $block{else}{body} ], |
188
|
|
|
|
|
|
|
), |
189
|
|
|
|
|
|
|
$name->clone( |
190
|
|
|
|
|
|
|
arity => 'block_body', |
191
|
|
|
|
|
|
|
first => [ |
192
|
|
|
|
|
|
|
$self->new_vars($name->clone, $self->iterator_index), |
193
|
|
|
|
|
|
|
], |
194
|
35
|
|
|
|
|
1132
|
second => [ $block{if}{body} ], |
195
|
|
|
|
|
|
|
), |
196
|
|
|
|
|
|
|
), |
197
|
|
|
|
|
|
|
]; |
198
|
|
|
|
|
|
|
|
199
|
35
|
|
|
|
|
1336
|
my $var = $name->clone(arity => 'variable'); |
200
|
|
|
|
|
|
|
return $self->compile_ast( |
201
|
|
|
|
|
|
|
$self->make_ternary( |
202
|
|
|
|
|
|
|
$self->is_code_ref($var->clone), |
203
|
|
|
|
|
|
|
$self->run_code( |
204
|
|
|
|
|
|
|
$var->clone, |
205
|
|
|
|
|
|
|
$block{if}{raw_text}->clone, |
206
|
|
|
|
|
|
|
$block{if}{open_tag}->clone, |
207
|
|
|
|
|
|
|
$block{if}{close_tag}->clone, |
208
|
35
|
|
|
|
|
744
|
), |
209
|
|
|
|
|
|
|
$self->parser->symbol('(for)')->clone( |
210
|
|
|
|
|
|
|
arity => 'for', |
211
|
|
|
|
|
|
|
first => $iterations, |
212
|
|
|
|
|
|
|
second => [$loop_var], |
213
|
|
|
|
|
|
|
third => $body_block, |
214
|
|
|
|
|
|
|
), |
215
|
|
|
|
|
|
|
), |
216
|
|
|
|
|
|
|
); |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub _generate_unary { |
220
|
1071
|
|
|
1071
|
|
108819
|
my $self = shift; |
221
|
1071
|
|
|
|
|
1495
|
my ($node) = @_; |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# XXX copied from Text::Xslate::Compiler because it uses a hardcoded list |
224
|
|
|
|
|
|
|
# of unary ops |
225
|
1071
|
100
|
|
|
|
3141
|
if ($self->is_unary($node->id)) { |
226
|
1001
|
|
|
|
|
3703
|
my @code = ( |
227
|
|
|
|
|
|
|
$self->compile_ast($node->first), |
228
|
|
|
|
|
|
|
$self->opcode($node->id) |
229
|
|
|
|
|
|
|
); |
230
|
|
|
|
|
|
|
# render_string can't be constant folded, because it depends on the |
231
|
|
|
|
|
|
|
# current vars |
232
|
1001
|
0
|
33
|
|
|
121100
|
if ($Text::Xslate::Compiler::OPTIMIZE and $self->_code_is_literal(@code) && $node->id ne 'render_string' && $node->id ne 'find_file') { |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
233
|
0
|
|
|
|
|
0
|
$self->_fold_constants(\@code); |
234
|
|
|
|
|
|
|
} |
235
|
1001
|
|
|
|
|
9666
|
return @code; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
else { |
238
|
70
|
|
|
|
|
247
|
return $self->SUPER::_generate_unary(@_); |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub is_unary { |
243
|
1071
|
|
|
1071
|
0
|
1319
|
my $self = shift; |
244
|
1071
|
|
|
|
|
1438
|
my ($id) = @_; |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
my %unary = ( |
247
|
1071
|
|
|
|
|
1613
|
map { $_ => 1 } qw(builtin_is_array_ref builtin_is_hash_ref is_code_ref |
|
4284
|
|
|
|
|
9159
|
|
248
|
|
|
|
|
|
|
find_file) |
249
|
|
|
|
|
|
|
); |
250
|
|
|
|
|
|
|
|
251
|
1071
|
|
|
|
|
4081
|
return $unary{$id}; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub _generate_array_length { |
255
|
70
|
|
|
70
|
|
1765
|
my $self = shift; |
256
|
70
|
|
|
|
|
103
|
my ($node) = @_; |
257
|
|
|
|
|
|
|
|
258
|
70
|
|
|
|
|
288
|
my $max_index = $self->parser->symbol('(max_index)')->clone( |
259
|
|
|
|
|
|
|
id => 'max_index', |
260
|
|
|
|
|
|
|
arity => 'unary', |
261
|
|
|
|
|
|
|
first => $node->first, |
262
|
|
|
|
|
|
|
); |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
return ( |
265
|
70
|
|
|
|
|
2399
|
$self->compile_ast($max_index), |
266
|
|
|
|
|
|
|
$self->opcode('move_to_sb'), |
267
|
|
|
|
|
|
|
$self->opcode('literal', 1), |
268
|
|
|
|
|
|
|
$self->opcode('add'), |
269
|
|
|
|
|
|
|
); |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
sub _generate_run_code { |
273
|
786
|
|
|
786
|
|
18650
|
my $self = shift; |
274
|
786
|
|
|
|
|
1112
|
my ($node) = @_; |
275
|
|
|
|
|
|
|
|
276
|
786
|
|
|
|
|
2039
|
my $to_render = $node->clone(arity => 'call'); |
277
|
|
|
|
|
|
|
|
278
|
786
|
100
|
|
|
|
18040
|
if ($node->third) { |
279
|
35
|
|
|
|
|
49
|
my ($open_tag, $close_tag) = @{ $node->third }; |
|
35
|
|
|
|
|
92
|
|
280
|
35
|
|
|
|
|
155
|
$to_render = $self->make_ternary( |
281
|
|
|
|
|
|
|
$self->parser->symbol('==')->clone( |
282
|
|
|
|
|
|
|
arity => 'binary', |
283
|
|
|
|
|
|
|
first => $close_tag->clone, |
284
|
|
|
|
|
|
|
second => $self->literal('}}'), |
285
|
|
|
|
|
|
|
), |
286
|
|
|
|
|
|
|
$to_render, |
287
|
|
|
|
|
|
|
$self->join('{{= ', $open_tag, ' ', $close_tag, ' =}}', $to_render) |
288
|
|
|
|
|
|
|
); |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
# XXX turn this into an opcode |
292
|
786
|
|
|
|
|
2840
|
my $render_string = $self->call( |
293
|
|
|
|
|
|
|
$node, |
294
|
|
|
|
|
|
|
'(render_string)', |
295
|
|
|
|
|
|
|
$to_render, |
296
|
|
|
|
|
|
|
$self->vars, |
297
|
|
|
|
|
|
|
); |
298
|
|
|
|
|
|
|
|
299
|
786
|
|
|
|
|
2776
|
return $self->compile_ast($render_string); |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
sub _generate_new_vars { |
303
|
36
|
|
|
36
|
|
972
|
my $self = shift; |
304
|
36
|
|
|
|
|
57
|
my ($node) = @_; |
305
|
|
|
|
|
|
|
|
306
|
36
|
|
|
|
|
170
|
my ($vars, $value, $i) = ($node->first, $node->second, $node->third); |
307
|
|
|
|
|
|
|
|
308
|
36
|
|
|
|
|
89
|
my $lvar_id = $self->lvar_id; |
309
|
36
|
|
|
|
|
103
|
local $self->{lvar_id} = $self->lvar_use(1); |
310
|
|
|
|
|
|
|
|
311
|
36
|
|
|
|
|
195
|
my @code; |
312
|
|
|
|
|
|
|
|
313
|
36
|
|
|
|
|
96
|
push @code, $self->compile_ast($value); |
314
|
36
|
|
|
|
|
12179
|
push @code, $self->opcode('save_to_lvar', $lvar_id); |
315
|
36
|
|
|
|
|
653
|
my $lvar_value = $value->clone(arity => 'lvar', id => $lvar_id); |
316
|
|
|
|
|
|
|
|
317
|
36
|
100
|
|
|
|
1107
|
if ($i) { |
318
|
35
|
|
|
|
|
147
|
my $value_at_index = $value->clone( |
319
|
|
|
|
|
|
|
arity => 'field', |
320
|
|
|
|
|
|
|
first => $value->clone, |
321
|
|
|
|
|
|
|
second => $i->clone, |
322
|
|
|
|
|
|
|
); |
323
|
|
|
|
|
|
|
|
324
|
35
|
|
|
|
|
1981
|
push @code, $self->compile_ast( |
325
|
|
|
|
|
|
|
$self->make_ternary( |
326
|
|
|
|
|
|
|
$self->is_array_ref($lvar_value->clone), |
327
|
|
|
|
|
|
|
$self->save_lvar( |
328
|
|
|
|
|
|
|
$lvar_id, |
329
|
|
|
|
|
|
|
$self->make_ternary( |
330
|
|
|
|
|
|
|
$self->is_hash_ref($value_at_index->clone), |
331
|
|
|
|
|
|
|
$self->merge_hash( |
332
|
|
|
|
|
|
|
$self->make_hash( |
333
|
|
|
|
|
|
|
$self->literal('.'), |
334
|
|
|
|
|
|
|
$value_at_index->clone, |
335
|
|
|
|
|
|
|
), |
336
|
|
|
|
|
|
|
$value_at_index->clone, |
337
|
|
|
|
|
|
|
), |
338
|
|
|
|
|
|
|
$self->make_hash( |
339
|
|
|
|
|
|
|
$self->literal('.'), |
340
|
|
|
|
|
|
|
$value_at_index->clone, |
341
|
|
|
|
|
|
|
), |
342
|
|
|
|
|
|
|
), |
343
|
|
|
|
|
|
|
), |
344
|
|
|
|
|
|
|
), |
345
|
|
|
|
|
|
|
); |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
else { |
348
|
1
|
|
|
|
|
5
|
push @code, $self->compile_ast( |
349
|
|
|
|
|
|
|
$self->make_ternary( |
350
|
|
|
|
|
|
|
$self->is_array_ref($lvar_value->clone), |
351
|
|
|
|
|
|
|
$self->save_lvar( |
352
|
|
|
|
|
|
|
$lvar_id, |
353
|
|
|
|
|
|
|
$self->make_hash( |
354
|
|
|
|
|
|
|
$self->literal('.'), |
355
|
|
|
|
|
|
|
$value->clone, |
356
|
|
|
|
|
|
|
), |
357
|
|
|
|
|
|
|
), |
358
|
|
|
|
|
|
|
), |
359
|
|
|
|
|
|
|
); |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
36
|
100
|
|
|
|
25141
|
push @code, $self->compile_ast( |
363
|
|
|
|
|
|
|
$self->save_lvar( |
364
|
|
|
|
|
|
|
$lvar_id, |
365
|
|
|
|
|
|
|
$self->make_ternary( |
366
|
|
|
|
|
|
|
$self->is_hash_ref($lvar_value->clone), |
367
|
|
|
|
|
|
|
$self->merge_hash( |
368
|
|
|
|
|
|
|
($i |
369
|
|
|
|
|
|
|
? ( |
370
|
|
|
|
|
|
|
$self->make_hash( |
371
|
|
|
|
|
|
|
$self->literal('@index'), $i->clone |
372
|
|
|
|
|
|
|
) |
373
|
|
|
|
|
|
|
) |
374
|
|
|
|
|
|
|
: ()), |
375
|
|
|
|
|
|
|
$vars->clone, |
376
|
|
|
|
|
|
|
$lvar_value->clone, |
377
|
|
|
|
|
|
|
$self->make_hash( |
378
|
|
|
|
|
|
|
$self->literal('..'), |
379
|
|
|
|
|
|
|
$vars->clone, |
380
|
|
|
|
|
|
|
), |
381
|
|
|
|
|
|
|
), |
382
|
|
|
|
|
|
|
$vars->clone, |
383
|
|
|
|
|
|
|
), |
384
|
|
|
|
|
|
|
), |
385
|
|
|
|
|
|
|
); |
386
|
|
|
|
|
|
|
|
387
|
36
|
|
|
|
|
15345
|
push @code, $self->opcode('load_lvar', $lvar_id); |
388
|
|
|
|
|
|
|
|
389
|
36
|
|
|
|
|
1666
|
return @code; |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
sub _generate_lvar { |
393
|
108
|
|
|
108
|
|
10612
|
my $self = shift; |
394
|
108
|
|
|
|
|
152
|
my ($node) = @_; |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
return ( |
397
|
108
|
|
|
|
|
391
|
$self->opcode('load_lvar', $node->id), |
398
|
|
|
|
|
|
|
); |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
sub _generate_save_lvar { |
402
|
72
|
|
|
72
|
|
2013
|
my $self = shift; |
403
|
72
|
|
|
|
|
110
|
my ($node) = @_; |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
return ( |
406
|
72
|
|
|
|
|
260
|
$self->compile_ast($node->first), |
407
|
|
|
|
|
|
|
$self->opcode('save_to_lvar', $node->id), |
408
|
|
|
|
|
|
|
); |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub _generate_merge_hash { |
412
|
142
|
|
|
142
|
|
2688
|
my $self = shift; |
413
|
142
|
|
|
|
|
202
|
my ($node) = @_; |
414
|
|
|
|
|
|
|
|
415
|
142
|
|
|
|
|
327
|
my $lvar_id = $self->lvar_id; |
416
|
142
|
|
|
|
|
351
|
local $self->{lvar_id} = $self->lvar_use(1); |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
return ( |
419
|
142
|
|
|
|
|
990
|
$self->compile_ast($node->first), |
420
|
|
|
|
|
|
|
$self->opcode('save_to_lvar', $lvar_id), |
421
|
|
|
|
|
|
|
$self->compile_ast($node->second), |
422
|
|
|
|
|
|
|
$self->opcode('move_to_sb'), |
423
|
|
|
|
|
|
|
$self->opcode('load_lvar', $lvar_id), |
424
|
|
|
|
|
|
|
$self->opcode('merge_hash'), |
425
|
|
|
|
|
|
|
); |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
sub join { |
429
|
35
|
|
|
35
|
0
|
1775
|
my $self = shift; |
430
|
35
|
|
|
|
|
95
|
my (@args) = @_; |
431
|
|
|
|
|
|
|
|
432
|
35
|
|
|
|
|
60
|
@args = map { $self->literalize($_) } @args; |
|
210
|
|
|
|
|
4390
|
|
433
|
|
|
|
|
|
|
|
434
|
35
|
|
|
|
|
714
|
my $joined = shift @args; |
435
|
35
|
|
|
|
|
78
|
for my $arg (@args) { |
436
|
175
|
|
|
|
|
4749
|
$joined = $self->parser->symbol('~')->clone( |
437
|
|
|
|
|
|
|
arity => 'binary', |
438
|
|
|
|
|
|
|
first => $joined, |
439
|
|
|
|
|
|
|
second => $arg, |
440
|
|
|
|
|
|
|
); |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
|
443
|
35
|
|
|
|
|
1052
|
return $joined; |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
sub literalize { |
447
|
210
|
|
|
210
|
0
|
326
|
my $self = shift; |
448
|
210
|
|
|
|
|
297
|
my ($val) = @_; |
449
|
|
|
|
|
|
|
|
450
|
210
|
100
|
|
|
|
797
|
return $val->clone if blessed($val); |
451
|
105
|
|
|
|
|
211
|
return $self->literal($val); |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
sub call { |
455
|
820
|
|
|
820
|
0
|
22425
|
my $self = shift; |
456
|
820
|
|
|
|
|
1648
|
my ($node, $name, @args) = @_; |
457
|
|
|
|
|
|
|
|
458
|
820
|
|
|
|
|
2865
|
my $code = $self->parser->symbol('(name)')->clone( |
459
|
|
|
|
|
|
|
arity => 'name', |
460
|
|
|
|
|
|
|
id => $name, |
461
|
|
|
|
|
|
|
line => $node->line, |
462
|
|
|
|
|
|
|
); |
463
|
|
|
|
|
|
|
|
464
|
820
|
|
|
|
|
28638
|
return $self->parser->call($code, @args); |
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
sub make_ternary { |
468
|
1106
|
|
|
1106
|
0
|
33088
|
my $self = shift; |
469
|
1106
|
|
|
|
|
1698
|
my ($if, $then, $else) = @_; |
470
|
1106
|
|
|
|
|
3918
|
return $self->parser->symbol('?:')->clone( |
471
|
|
|
|
|
|
|
arity => 'if', |
472
|
|
|
|
|
|
|
first => $if, |
473
|
|
|
|
|
|
|
second => $then, |
474
|
|
|
|
|
|
|
third => $else, |
475
|
|
|
|
|
|
|
); |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
sub vars { |
479
|
898
|
|
|
898
|
0
|
1151
|
my $self = shift; |
480
|
898
|
|
|
|
|
3138
|
return $self->parser->symbol('(vars)')->clone(arity => 'vars'); |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
sub iterator_index { |
484
|
35
|
|
|
35
|
0
|
2243
|
my $self = shift; |
485
|
|
|
|
|
|
|
|
486
|
35
|
|
|
|
|
138
|
return $self->parser->symbol('(iterator)')->clone( |
487
|
|
|
|
|
|
|
arity => 'iterator', |
488
|
|
|
|
|
|
|
id => '$~(loop_var)', |
489
|
|
|
|
|
|
|
first => $self->parser->symbol('(loop_var)')->clone, |
490
|
|
|
|
|
|
|
), |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
sub check_lambda { |
494
|
751
|
|
|
751
|
0
|
991
|
my $self = shift; |
495
|
751
|
|
|
|
|
1016
|
my ($var) = @_; |
496
|
|
|
|
|
|
|
|
497
|
751
|
|
|
|
|
1997
|
return $self->make_ternary( |
498
|
|
|
|
|
|
|
$self->is_code_ref($var->clone), |
499
|
|
|
|
|
|
|
$self->run_code($var->clone), |
500
|
|
|
|
|
|
|
$var, |
501
|
|
|
|
|
|
|
); |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
sub is_array_ref { |
505
|
141
|
|
|
141
|
0
|
3268
|
my $self = shift; |
506
|
141
|
|
|
|
|
204
|
my ($var) = @_; |
507
|
|
|
|
|
|
|
|
508
|
141
|
|
|
|
|
589
|
return $self->parser->symbol('(is_array_ref)')->clone( |
509
|
|
|
|
|
|
|
id => 'builtin_is_array_ref', |
510
|
|
|
|
|
|
|
arity => 'unary', |
511
|
|
|
|
|
|
|
first => $var, |
512
|
|
|
|
|
|
|
); |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
sub is_hash_ref { |
516
|
71
|
|
|
71
|
0
|
2227
|
my $self = shift; |
517
|
71
|
|
|
|
|
104
|
my ($var) = @_; |
518
|
|
|
|
|
|
|
|
519
|
71
|
|
|
|
|
273
|
return $self->parser->symbol('(is_hash_ref)')->clone( |
520
|
|
|
|
|
|
|
id => 'builtin_is_hash_ref', |
521
|
|
|
|
|
|
|
arity => 'unary', |
522
|
|
|
|
|
|
|
first => $var, |
523
|
|
|
|
|
|
|
); |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
sub is_code_ref { |
527
|
786
|
|
|
786
|
0
|
13465
|
my $self = shift; |
528
|
786
|
|
|
|
|
1099
|
my ($var) = @_; |
529
|
|
|
|
|
|
|
|
530
|
786
|
|
|
|
|
2813
|
return $self->parser->symbol('(is_code_ref)')->clone( |
531
|
|
|
|
|
|
|
id => 'is_code_ref', |
532
|
|
|
|
|
|
|
arity => 'unary', |
533
|
|
|
|
|
|
|
first => $var, |
534
|
|
|
|
|
|
|
); |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
sub make_array { |
538
|
70
|
|
|
70
|
0
|
1857
|
my $self = shift; |
539
|
70
|
|
|
|
|
150
|
my (@contents) = @_; |
540
|
|
|
|
|
|
|
|
541
|
70
|
|
|
|
|
246
|
return $self->parser->symbol('[')->clone( |
542
|
|
|
|
|
|
|
arity => 'composer', |
543
|
|
|
|
|
|
|
first => \@contents, |
544
|
|
|
|
|
|
|
); |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
sub make_hash { |
548
|
184
|
|
|
184
|
0
|
5922
|
my $self = shift; |
549
|
184
|
|
|
|
|
367
|
my (@contents) = @_; |
550
|
|
|
|
|
|
|
|
551
|
184
|
|
|
|
|
682
|
return $self->parser->symbol('{')->clone( |
552
|
|
|
|
|
|
|
arity => 'composer', |
553
|
|
|
|
|
|
|
first => \@contents, |
554
|
|
|
|
|
|
|
); |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
sub is_falsy { |
558
|
70
|
|
|
70
|
0
|
1246
|
my $self = shift; |
559
|
70
|
|
|
|
|
105
|
my ($node) = @_; |
560
|
|
|
|
|
|
|
|
561
|
70
|
|
|
|
|
195
|
return $self->not( |
562
|
|
|
|
|
|
|
$self->make_ternary( |
563
|
|
|
|
|
|
|
$self->is_array_ref($node->clone), |
564
|
|
|
|
|
|
|
$self->array_length($node->clone), |
565
|
|
|
|
|
|
|
$node |
566
|
|
|
|
|
|
|
) |
567
|
|
|
|
|
|
|
); |
568
|
|
|
|
|
|
|
} |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
sub not { |
571
|
70
|
|
|
70
|
0
|
2118
|
my $self = shift; |
572
|
70
|
|
|
|
|
102
|
my ($node) = @_; |
573
|
|
|
|
|
|
|
|
574
|
70
|
|
|
|
|
281
|
return $self->parser->symbol('!')->clone( |
575
|
|
|
|
|
|
|
arity => 'unary', |
576
|
|
|
|
|
|
|
first => $node, |
577
|
|
|
|
|
|
|
); |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
sub array_length { |
581
|
70
|
|
|
70
|
0
|
3211
|
my $self = shift; |
582
|
70
|
|
|
|
|
105
|
my ($node) = @_; |
583
|
|
|
|
|
|
|
|
584
|
70
|
|
|
|
|
248
|
return $self->parser->symbol('(array_length)')->clone( |
585
|
|
|
|
|
|
|
arity => 'array_length', |
586
|
|
|
|
|
|
|
first => $node, |
587
|
|
|
|
|
|
|
); |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
sub run_code { |
591
|
786
|
|
|
786
|
0
|
36318
|
my $self = shift; |
592
|
786
|
|
|
|
|
1259
|
my ($code, $raw_text, $open_tag, $close_tag) = @_; |
593
|
|
|
|
|
|
|
|
594
|
786
|
100
|
|
|
|
2734
|
return $self->parser->symbol('(run_code)')->clone( |
595
|
|
|
|
|
|
|
arity => 'run_code', |
596
|
|
|
|
|
|
|
first => $code, |
597
|
|
|
|
|
|
|
(@_ > 1 |
598
|
|
|
|
|
|
|
? (second => [ $raw_text ], third => [ $open_tag, $close_tag ]) |
599
|
|
|
|
|
|
|
: (second => [])), |
600
|
|
|
|
|
|
|
); |
601
|
|
|
|
|
|
|
} |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
sub new_vars { |
604
|
36
|
|
|
36
|
0
|
1904
|
my $self = shift; |
605
|
36
|
|
|
|
|
60
|
my ($value, $i) = @_; |
606
|
|
|
|
|
|
|
|
607
|
36
|
|
|
|
|
101
|
return $value->clone( |
608
|
|
|
|
|
|
|
arity => 'new_vars', |
609
|
|
|
|
|
|
|
first => $self->vars, |
610
|
|
|
|
|
|
|
second => $value, |
611
|
|
|
|
|
|
|
third => $i, |
612
|
|
|
|
|
|
|
); |
613
|
|
|
|
|
|
|
} |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
sub save_lvar { |
616
|
72
|
|
|
72
|
0
|
1970
|
my $self = shift; |
617
|
72
|
|
|
|
|
116
|
my ($id, $value) = @_; |
618
|
|
|
|
|
|
|
|
619
|
72
|
|
|
|
|
201
|
return $value->clone( |
620
|
|
|
|
|
|
|
arity => 'save_lvar', |
621
|
|
|
|
|
|
|
id => $id, |
622
|
|
|
|
|
|
|
first => $value, |
623
|
|
|
|
|
|
|
); |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
sub merge_hash { |
627
|
71
|
|
|
71
|
0
|
2520
|
my $self = shift; |
628
|
71
|
|
|
|
|
138
|
my (@hashes) = @_; |
629
|
|
|
|
|
|
|
|
630
|
71
|
|
|
|
|
117
|
my $merged = shift @hashes; |
631
|
71
|
|
|
|
|
142
|
for my $hash (@hashes) { |
632
|
142
|
|
|
|
|
1791
|
$merged = $self->merge_single_hash($merged, $hash); |
633
|
|
|
|
|
|
|
} |
634
|
|
|
|
|
|
|
|
635
|
71
|
|
|
|
|
1711
|
return $merged; |
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
sub merge_single_hash { |
639
|
142
|
|
|
142
|
0
|
189
|
my $self = shift; |
640
|
142
|
|
|
|
|
186
|
my ($left, $right) = @_; |
641
|
|
|
|
|
|
|
|
642
|
142
|
|
|
|
|
393
|
return $left->clone( |
643
|
|
|
|
|
|
|
arity => 'merge_hash', |
644
|
|
|
|
|
|
|
first => $left, |
645
|
|
|
|
|
|
|
second => $right, |
646
|
|
|
|
|
|
|
); |
647
|
|
|
|
|
|
|
} |
648
|
|
|
|
|
|
|
|
649
|
382
|
|
|
382
|
0
|
10885
|
sub literal { shift->parser->literal(@_) } |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
652
|
12
|
|
|
12
|
|
73
|
no Mouse; |
|
12
|
|
|
|
|
21
|
|
|
12
|
|
|
|
|
65
|
|
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
=for Pod::Coverage |
655
|
|
|
|
|
|
|
define_helper |
656
|
|
|
|
|
|
|
find_file |
657
|
|
|
|
|
|
|
is_unary |
658
|
|
|
|
|
|
|
join |
659
|
|
|
|
|
|
|
literalize |
660
|
|
|
|
|
|
|
call |
661
|
|
|
|
|
|
|
make_ternary |
662
|
|
|
|
|
|
|
vars |
663
|
|
|
|
|
|
|
iterator_index |
664
|
|
|
|
|
|
|
check_lambda |
665
|
|
|
|
|
|
|
is_array_ref |
666
|
|
|
|
|
|
|
is_hash_ref |
667
|
|
|
|
|
|
|
is_code_ref |
668
|
|
|
|
|
|
|
make_array |
669
|
|
|
|
|
|
|
make_hash |
670
|
|
|
|
|
|
|
is_falsy |
671
|
|
|
|
|
|
|
not |
672
|
|
|
|
|
|
|
array_length |
673
|
|
|
|
|
|
|
run_code |
674
|
|
|
|
|
|
|
new_vars |
675
|
|
|
|
|
|
|
save_lvar |
676
|
|
|
|
|
|
|
merge_hash |
677
|
|
|
|
|
|
|
merge_single_hash |
678
|
|
|
|
|
|
|
literal |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
=cut |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
1; |