File Coverage

blib/lib/Template/Alloy/Compile.pm
Criterion Covered Total %
statement 348 368 94.5
branch 87 112 77.6
condition 35 63 55.5
subroutine 51 54 94.4
pod 2 40 5.0
total 523 637 82.1


line stmt bran cond sub pod time code
1             package Template::Alloy::Compile;
2              
3             =head1 NAME
4              
5             Template::Alloy::Compile - Compile role - allows for compiling the AST to perl code
6              
7             =cut
8              
9 9     9   75 use strict;
  9         21  
  9         359  
10 9     9   54 use warnings;
  9         19  
  9         305  
11 9     9   48 use Template::Alloy;
  9         92  
  9         68  
12 9     9   55 use Template::Alloy::Iterator;
  9         22  
  9         66315  
13              
14             our $VERSION = $Template::Alloy::VERSION;
15             our $INDENT = ' ' x 4;
16             our $DIRECTIVES = {
17             BLOCK => \&compile_BLOCK,
18             BREAK => \&compile_LAST,
19             CALL => \&compile_CALL,
20             CASE => undef,
21             CATCH => undef,
22             CLEAR => \&compile_CLEAR,
23             '#' => sub {},
24             COMMENT => sub {},
25             CONFIG => \&compile_CONFIG,
26             DEBUG => \&compile_DEBUG,
27             DEFAULT => \&compile_DEFAULT,
28             DUMP => \&compile_DUMP,
29             ELSE => undef,
30             ELSIF => undef,
31             END => sub {},
32             EVAL => \&compile_EVAL,
33             FILTER => \&compile_FILTER,
34             '|' => \&compile_FILTER,
35             FINAL => undef,
36             FOR => \&compile_FOR,
37             FOREACH => \&compile_FOR,
38             GET => \&compile_GET,
39             IF => \&compile_IF,
40             INCLUDE => \&compile_INCLUDE,
41             INSERT => \&compile_INSERT,
42             JS => \&compile_JS,
43             LAST => \&compile_LAST,
44             LOOP => \&compile_LOOP,
45             MACRO => \&compile_MACRO,
46             META => \&compile_META,
47             NEXT => \&compile_NEXT,
48             PERL => \&compile_PERL,
49             PROCESS => \&compile_PROCESS,
50             RAWPERL => \&compile_RAWPERL,
51             RETURN => \&compile_RETURN,
52             SET => \&compile_SET,
53             STOP => \&compile_STOP,
54             SWITCH => \&compile_SWITCH,
55             TAGS => sub {},
56             THROW => \&compile_THROW,
57             TRY => \&compile_TRY,
58             UNLESS => \&compile_UNLESS,
59             USE => \&compile_USE,
60             VIEW => \&compile_VIEW,
61             WHILE => \&compile_WHILE,
62             WRAPPER => \&compile_WRAPPER,
63             };
64              
65 0     0 0 0 sub new { die "This class is a role for use by packages such as Template::Alloy" }
66              
67             sub load_perl {
68 1745     1745 0 3903 my ($self, $doc) = @_;
69              
70             ### first look for a compiled perl document
71 1745         2748 my $perl;
72 1745 100       4194 if ($doc->{'_filename'}) {
73 1744   66     6416 $doc->{'modtime'} ||= (stat $doc->{'_filename'})[9];
74 1744 100 100     7227 if ($self->{'COMPILE_DIR'} || $self->{'COMPILE_EXT'}) {
75 9         16 my $file = $doc->{'_filename'};
76 9 100       24 if ($self->{'COMPILE_DIR'}) {
    100          
77 4 50       17 $file =~ y|:|/| if $^O eq 'MSWin32';
78 4         14 $file = $self->{'COMPILE_DIR'} .'/'. $file;
79             } elsif ($doc->{'_is_str_ref'}) {
80 1   50     5 $file = ($self->include_paths->[0] || '.') .'/'. $file;
81             }
82 9 100       32 $file .= $self->{'COMPILE_EXT'} if defined($self->{'COMPILE_EXT'});
83 9 50       25 $file .= $Template::Alloy::PERL_COMPILE_EXT if defined $Template::Alloy::PERL_COMPILE_EXT;
84              
85 9 100 33     145 if (-e $file && ($doc->{'_is_str_ref'} || (stat $file)[9] == $doc->{'modtime'})) {
      66        
86 1         6 $perl = $self->slurp($file);
87             } else {
88 8         33 $doc->{'_compile_filename'} = $file;
89             }
90             }
91             }
92              
93 1745   66     6491 $perl ||= $self->compile_template($doc);
94              
95             ### save a cache on the fileside as asked
96 1697 100       4448 if ($doc->{'_compile_filename'}) {
97 8         18 my $dir = $doc->{'_compile_filename'};
98 8         63 $dir =~ s|/[^/]+$||;
99 8 50       136 if (! -d $dir) {
100 0         0 require File::Path;
101 0         0 File::Path::mkpath($dir);
102             }
103 8 50       494 open(my $fh, ">", $doc->{'_compile_filename'}) || $self->throw('compile', "Could not open file \"$doc->{'_compile_filename'}\" for writing: $!");
104             ### todo - think about locking
105 8 100 66     47 if ($self->{'ENCODING'} && eval { require Encode } && defined &Encode::encode) {
  1   66     13  
106 1         3 print {$fh} Encode::encode($self->{'ENCODING'}, $$perl);
  1         7  
107             } else {
108 7         11 print {$fh} $$perl;
  7         37  
109             }
110 8         285 close $fh;
111 8         165 utime $doc->{'modtime'}, $doc->{'modtime'}, $doc->{'_compile_filename'};
112             }
113              
114 1697     1   344409 $perl = eval $$perl;
  1     1   9  
  1     1   3  
  1     1   126  
  1     1   7  
  1     1   3  
  1     1   101  
  1         8  
  1         3  
  1         79  
  1         6  
  1         3  
  1         97  
  1         8  
  1         3  
  1         133  
  1         8  
  1         3  
  1         137  
  1         8  
  1         3  
  1         140  
115 1697 0 33     6232 $self->throw('compile', "Trouble loading compiled perl: $@") if ! $perl && $@;
116              
117 1697         8246 return $perl;
118             }
119              
120             ###----------------------------------------------------------------###
121              
122             sub compile_template {
123 1744     1744 0 3161 my ($self, $doc) = @_;
124              
125 1744         4016 local $self->{'_component'} = $doc;
126 1744   66     7031 my $tree = $doc->{'_tree'} ||= $self->load_tree($doc);
127              
128 1696         5149 local $self->{'_blocks'} = '';
129 1696         3510 local $self->{'_meta'} = '';
130              
131 1696         4705 my $code = $self->compile_tree($tree, $INDENT);
132 1696 100       4427 $self->{'_blocks'} .= "\n" if $self->{'_blocks'};
133 1696 100       3794 $self->{'_meta'} .= "\n" if $self->{'_meta'};
134              
135 1696   100     3890 my $file = $doc->{'_filename'} || '';
136 1696         3725 $file =~ s/\'/\\\'/g;
137              
138             my $str = "# Generated by ".__PACKAGE__." v$VERSION on ".localtime()."
139              
140             my \$file = '$file';
141             my \$blocks = {$self->{'_blocks'}};
142             my \$meta = {$self->{'_meta'}};
143             my \$code = sub {
144             ${INDENT}my (\$self, \$out_ref, \$var) = \@_;"
145             .($self->{'_blocks'} ? "\n${INDENT}\@{ \$self->{'BLOCKS'} }{ keys %\$blocks } = values %\$blocks;" : "")
146 1696 100       64611 .($self->{'_meta'} ? "\n${INDENT}\@{ \$self->{'_component'} }{ keys %\$meta } = values %\$meta;" : "")
    100          
147             ."$code
148              
149             ${INDENT}return 1;
150             };
151              
152             {
153             ${INDENT}blocks => \$blocks,
154             ${INDENT}meta => \$meta,
155             ${INDENT}code => \$code,
156             };\n";
157             # print $str;
158 1696         13348 return \$str;
159             }
160              
161             ###----------------------------------------------------------------###
162              
163             sub _node_info {
164 3822     3822   7313 my ($self, $node, $indent) = @_;
165 3822   50     8082 my $doc = $self->{'_component'} || return '';
166 3822   33     7748 $doc->{'_content'} ||= $self->slurp($doc->{'_filename'});
167 3822         10097 my ($line, $char) = $self->get_line_number_by_index($doc, $node->[1], 'include_chars');
168 3822         16888 return "\n\n${indent}# \"$node->[0]\" Line $line char $char (chars $node->[1] to $node->[2])";
169             }
170              
171             sub compile_tree {
172 2341     2341 1 5369 my ($self, $tree, $indent) = @_;
173 2341         3972 my $code = '';
174             # node contains (0: DIRECTIVE,
175             # 1: start_index,
176             # 2: end_index,
177             # 3: parsed tag details,
178             # 4: sub tree for block types
179             # 5: continuation sub trees for sub continuation block types (elsif, else, etc)
180             # 6: flag to capture next directive
181 2341         3735 my @doc;
182             my $func;
183 2341         4983 for my $node (@$tree) {
184              
185             # text nodes are just the bare text
186 5083 100       10968 if (! ref $node) {
187 1359         2282 my $copy = $node; # must make a copy before modification
188 1359         2760 $copy =~ s/([\'\\])/\\$1/g;
189 1359         3001 $code .= "\n\n${indent}\$\$out_ref .= '$copy';";
190 1359         2567 next;
191             }
192              
193 3724 100 66     8733 if ($self->{'_debug_dirs'} && ! $self->{'_debug_off'}) {
194 8         28 my $info = $self->node_info($node);
195 8         15 my ($file, $line, $text) = @{ $info }{qw(file line text)};
  8         24  
196 8         34 s/\'/\\\'/g foreach $file, $line, $text;
197 8         44 $code .= "\n
198             ${indent}if (\$self->{'_debug_dirs'} && ! \$self->{'_debug_off'}) { # DEBUG
199             ${indent}${INDENT}my \$info = {file => '$file', line => '$line', text => '$text'};
200             ${indent}${INDENT}my \$format = \$self->{'_debug_format'} || \$self->{'DEBUG_FORMAT'} || \"\\n## \\\$file line \\\$line : [% \\\$text %] ##\\n\";
201             ${indent}${INDENT}\$format =~ s{\\\$(file|line|text)}{\$info->{\$1}}g;
202             ${indent}${INDENT}\$\$out_ref .= \$format;
203             ${indent}}";
204             }
205              
206 3724         7455 $code .= _node_info($self, $node, $indent);
207              
208 3724 50       10752 if ($func = $DIRECTIVES->{$node->[0]}) {
209 3724         8943 $func->($self, $node, \$code, $indent);
210             } else {
211             ### if the method isn't defined - delegate to the play directive (if there is one)
212 0         0 require Template::Alloy::Play;
213 0 0       0 if ($func = $Template::Alloy::Play::DIRECTIVES->{$node->[0]}) {
214 0         0 _compile_defer_to_play($self, $node, \$code, $indent);
215             } else {
216 0         0 die "Couldn't find compile or play method for directive \"$node->[0]\"";
217             }
218             }
219             }
220 2341         7720 return $code;
221             }
222              
223             sub compile_expr {
224 2559     2559 1 5164 my ($self, $var, $indent) = @_;
225 2559         6247 return "\$self->play_expr(".$self->ast_string($var).")";
226             }
227              
228             sub _compile_defer_to_play {
229 305     305   670 my ($self, $node, $str_ref, $indent) = @_;
230 305         622 my $directive = $node->[0];
231 305 50       1450 die "Invalid node name \"$directive\"" if $directive !~ /^\w+$/;
232              
233 305         1201 $$str_ref .= "
234             ${indent}require Template::Alloy::Play;
235             ${indent}\$var = ".$self->ast_string($node->[3]).";
236             ${indent}\$Template::Alloy::Play::DIRECTIVES->{'$directive'}->(\$self, \$var, ".$self->ast_string($node).", \$out_ref);";
237              
238 305         940 return;
239             }
240              
241             sub _is_empty_named_args {
242 35     35   66 my ($hash_ident) = @_;
243             # [[undef, '{}', 'key1', 'val1', 'key2, 'val2'], 0]
244 35         50 return @{ $hash_ident->[0] } <= 2;
  35         108  
245             }
246              
247             ###----------------------------------------------------------------###
248              
249             sub compile_BLOCK {
250 138     138 0 376 my ($self, $node, $str_ref, $indent) = @_;
251              
252 138         334 my $ref = \ $self->{'_blocks'};
253 138         291 my $name = $node->[3];
254 138         351 $name =~ s/\'/\\\'/g;
255 138         395 my $name2 = $self->{'_component'}->{'name'} .'/'. $node->[3];
256 138         266 $name2 =~ s/\'/\\\'/g;
257              
258 138         488 my $code = $self->compile_tree($node->[4], "$INDENT$INDENT$INDENT");
259              
260 138         1040 $$ref .= "
261             ${INDENT}'$name' => {
262             ${INDENT}${INDENT}name => '$name2',
263             ${INDENT}${INDENT}_filename => \$file,
264             ${INDENT}${INDENT}_perl => {code => sub {
265             ${INDENT}${INDENT}${INDENT}my (\$self, \$out_ref, \$var) = \@_;$code
266              
267             ${INDENT}${INDENT}${INDENT}return 1;
268             ${INDENT}${INDENT}}},
269             ${INDENT}},";
270              
271 138         345 return;
272             }
273              
274             sub compile_CALL {
275 26     26 0 68 my ($self, $node, $str_ref, $indent) = @_;
276 26         83 $$str_ref .= "\n${indent}scalar ".$self->compile_expr($node->[3], $indent).";";
277 26         70 return;
278             }
279              
280             sub compile_CLEAR {
281 7     7 0 16 my ($self, $node, $str_ref, $indent) = @_;
282 7         24 $$str_ref .= "
283             ${indent}\$\$out_ref = '';";
284             }
285              
286             sub compile_CONFIG {
287 41     41 0 99 my ($self, $node, $str_ref, $indent) = @_;
288 41         113 _compile_defer_to_play($self, $node, $str_ref, $indent);
289             }
290              
291             sub compile_DEBUG {
292 1     1 0 5 my ($self, $node, $str_ref, $indent) = @_;
293              
294 1         3 my $text = $node->[3]->[0];
295              
296 1 50       7 if ($text eq 'on') {
    50          
    50          
297 0         0 $$str_ref .= "\n${indent}delete \$self->{'_debug_off'};";
298             } elsif ($text eq 'off') {
299 0         0 $$str_ref .= "\n${indent}\$self->{'_debug_off'} = 1;";
300             } elsif ($text eq 'format') {
301 1         3 my $format = $node->[3]->[1];
302 1         3 $format =~ s/\'/\\\'/g;
303 1         6 $$str_ref .= "\n${indent}\$self->{'_debug_format'} = '$format';";
304             }
305 1         4 return;
306             }
307              
308             sub compile_DEFAULT {
309 3     3 0 8 my ($self, $node, $str_ref, $indent) = @_;
310 3         7 local $self->{'_is_default'} = 1;
311 3         12 $DIRECTIVES->{'SET'}->($self, $node, $str_ref, $indent);
312             }
313              
314             sub compile_DUMP {
315 28     28 0 65 my ($self, $node, $str_ref, $indent) = @_;
316 28         74 _compile_defer_to_play($self, $node, $str_ref, $indent);
317             }
318              
319             sub compile_GET {
320 1791     1791 0 3831 my ($self, $node, $str_ref, $indent) = @_;
321 1791         4685 $$str_ref .= "
322             $indent\$var = ".$self->compile_expr($node->[3], $indent).";
323             $indent\$\$out_ref .= defined(\$var) ? \$var : \$self->undefined_get(".$self->ast_string($node->[3]).");";
324 1791         5344 return;
325             }
326              
327             sub compile_EVAL {
328 9     9 0 25 my ($self, $node, $str_ref, $indent) = @_;
329 9         16 my ($named, @strs) = @{ $node->[3] };
  9         24  
330              
331             $$str_ref .= "
332 9         26 ${indent}foreach (".join(",\n", map {$self->ast_string($_)} @strs).") {
  9         26  
333             ${indent}${INDENT}my \$str = \$self->play_expr(\$_);
334             ${indent}${INDENT}next if ! defined \$str;
335             ${indent}${INDENT}\$\$out_ref .= \$self->play_expr([[undef, '-temp-', \$str], 0, '|', 'eval', [".$self->ast_string($named)."]]);
336             ${indent}}";
337             }
338              
339             sub compile_FILTER {
340 25     25 0 65 my ($self, $node, $str_ref, $indent) = @_;
341 25         44 my ($name, $filter) = @{ $node->[3] };
  25         66  
342 25 50       71 return if ! @$filter;
343              
344 25         103 $$str_ref .= "
345             ${indent}\$var = do {
346             ${indent}${INDENT}my \$filter = ".$self->ast_string($filter).";";
347              
348             ### allow for alias
349 25 100       77 if (length $name) {
350 6         13 $name =~ s/\'/\\\'/g;
351 6         20 $$str_ref .= "\n${indent}${INDENT}\$self->{'FILTERS'}->{'$name'} = \$filter; # alias for future calls\n";
352             }
353              
354 25         120 $$str_ref .= "
355             ${indent}${INDENT}my \$out = '';
356             ${indent}${INDENT}my \$out_ref = \\\$out;"
357             .$self->compile_tree($node->[4], "$indent$INDENT")."
358              
359             ${indent}\$out = \$self->play_expr([[undef, '-temp-', \$out], 0, '|', \@\$filter]);
360             ${indent}${INDENT}\$out;
361             ${indent}};
362             ${indent}\$\$out_ref .= \$var if defined \$var;";
363              
364             }
365              
366             sub compile_FOR {
367 90     90 0 213 my ($self, $node, $str_ref, $indent) = @_;
368              
369 90         150 my ($name, $items) = @{ $node->[3] };
  90         218  
370 90         222 local $self->{'_in_loop'} = 'FOREACH';
371 90         296 my $code = $self->compile_tree($node->[4], "$indent$INDENT");
372              
373 90         302 $$str_ref .= "\n${indent}do {
374             ${indent}my \$loop = ".$self->compile_expr($items, $indent).";
375             ${indent}\$loop = [] if ! defined \$loop;
376             ${indent}\$loop = \$self->iterator(\$loop) if ref(\$loop) !~ /Iterator\$/;
377             ${indent}local \$self->{'_vars'}->{'loop'} = \$loop;";
378 90 100       251 if (! defined $name) {
379 23         62 $$str_ref .= "
380             ${indent}my \$swap = \$self->{'_vars'};
381             ${indent}local \$self->{'_vars'} = my \$copy = {%\$swap};";
382             }
383              
384 90         314 $$str_ref .= "
385             ${indent}my (\$var, \$error) = \$loop->get_first;
386             ${indent}FOREACH: while (! \$error) {";
387              
388 90 100       202 if (defined $name) {
389 67         238 $$str_ref .= "\n$indent$INDENT\$self->set_variable(".$self->ast_string($name).", \$var);";
390             } else {
391 23         56 $$str_ref .= "\n$indent$INDENT\@\$copy{keys %\$var} = values %\$var if ref(\$var) eq 'HASH';";
392             }
393              
394 90         372 $$str_ref .= "$code
395             ${indent}${INDENT}(\$var, \$error) = \$loop->get_next;
396             ${indent}}
397             ${indent}};";
398 90         297 return;
399             }
400              
401 0     0 0 0 sub compile_FOREACH { shift->compile_FOR(@_) }
402              
403             sub compile_IF {
404 86     86 0 214 my ($self, $node, $str_ref, $indent) = @_;
405              
406 86         250 $$str_ref .= "\n${indent}if (".$self->compile_expr($node->[3], $indent).") {";
407 86         357 $$str_ref .= $self->compile_tree($node->[4], "$indent$INDENT");
408              
409 86         279 while ($node = $node->[5]) { # ELSE, ELSIF's
410 40         96 $$str_ref .= _node_info($self, $node, $indent);
411 40 100       105 if ($node->[0] eq 'ELSE') {
412 27         60 $$str_ref .= "\n${indent}} else {";
413 27         77 $$str_ref .= $self->compile_tree($node->[4], "$indent$INDENT");
414 27         55 last;
415             } else {
416 13         43 $$str_ref .= "\n${indent}} elsif (".$self->compile_expr($node->[3], $indent).") {";
417 13         50 $$str_ref .= $self->compile_tree($node->[4], "$indent$INDENT");
418             }
419             }
420 86         236 $$str_ref .= "\n${indent}}";
421             }
422              
423             sub compile_INCLUDE {
424 41     41 0 103 my ($self, $node, $str_ref, $indent) = @_;
425 41         103 _compile_defer_to_play($self, $node, $str_ref, $indent);
426             }
427              
428             sub compile_INSERT {
429 8     8 0 19 my ($self, $node, $str_ref, $indent) = @_;
430 8         21 _compile_defer_to_play($self, $node, $str_ref, $indent);
431             }
432              
433             sub compile_JS {
434 0     0 0 0 my ($self, $node, $str_ref, $indent) = @_;
435 0         0 _compile_defer_to_play($self, $node, $str_ref, $indent);
436             }
437              
438             sub compile_LAST {
439 3     3 0 13 my ($self, $node, $str_ref, $indent) = @_;
440 3   50     14 my $type = $self->{'_in_loop'} || die "Found LAST while not in FOR, FOREACH or WHILE";
441 3         11 $$str_ref .= "\n${indent}last $type;";
442 3         10 return;
443             }
444              
445             sub compile_LOOP {
446 21     21 0 52 my ($self, $node, $str_ref, $indent) = @_;
447 21         38 my $ref = $node->[3];
448 21 100       59 $ref = [$ref, 0] if ! ref $ref;
449              
450 21         65 $$str_ref .= "
451             ${indent}\$var = ".$self->compile_expr($ref, $indent).";
452             ${indent}if (\$var) {
453             ${indent}${INDENT}my \$global = ! \$self->{'SYNTAX'} || \$self->{'SYNTAX'} ne 'ht' || \$self->{'GLOBAL_VARS'};
454             ${indent}${INDENT}my \$items = ref(\$var) eq 'ARRAY' ? \$var : ref(\$var) eq 'HASH' ? [\$var] : [];
455             ${indent}${INDENT}my \$i = 0;
456             ${indent}${INDENT}for my \$ref (\@\$items) {
457             ${indent}${INDENT}${INDENT}\$self->throw('loop', 'Scalar value used in LOOP') if \$ref && ref(\$ref) ne 'HASH';
458             ${indent}${INDENT}${INDENT}local \$self->{'_vars'} = (! \$global) ? (\$ref || {}) : (ref(\$ref) eq 'HASH') ? {%{ \$self->{'_vars'} }, %\$ref} : \$self->{'_vars'};
459             ${indent}${INDENT}${INDENT}\@{ \$self->{'_vars'} }{qw(__counter__ __first__ __last__ __inner__ __odd__)}
460             ${indent}${INDENT}${INDENT}${INDENT}= (++\$i, (\$i == 1 ? 1 : 0), (\$i == \@\$items ? 1 : 0), (\$i == 1 || \$i == \@\$items ? 0 : 1), (\$i % 2) ? 1 : 0)
461             ${indent}${INDENT}${INDENT}${INDENT}${INDENT}if \$self->{'LOOP_CONTEXT_VARS'} && ! \$Template::Alloy::QR_PRIVATE;"
462             .$self->compile_tree($node->[4], "$indent$INDENT$INDENT")."
463              
464             ${indent}${INDENT}}
465             ${indent}}";
466             }
467              
468             sub compile_MACRO {
469 34     34 0 87 my ($self, $node, $str_ref, $indent) = @_;
470 34         68 my ($name, $args) = @{ $node->[3] };
  34         79  
471              
472             ### get the sub tree
473 34         67 my $sub_tree = $node->[4];
474 34 50 33     250 if (! $sub_tree || ! $sub_tree->[0]) {
    100 100        
475 0         0 $$str_ref .= "
476             ${indent}\$self->set_variable(".$self->ast_string($name).", undef);";
477 0         0 return;
478             } elsif (ref($sub_tree->[0]) && $sub_tree->[0]->[0] eq 'BLOCK') {
479 23         46 $sub_tree = $sub_tree->[0]->[4];
480             }
481              
482 34         113 my $code = $self->compile_tree($sub_tree, "$indent$INDENT");
483              
484 34         224 $$str_ref .= "
485             ${indent}do {
486             ${indent}my \$self_copy = \$self;
487             ${indent}eval {require Scalar::Util; Scalar::Util::weaken(\$self_copy)};
488             ${indent}\$var = sub {
489             ${indent}${INDENT}my \$copy = \$self_copy->{'_vars'};
490             ${indent}${INDENT}local \$self_copy->{'_vars'}= {%\$copy};
491              
492             ${indent}${INDENT}local \$self_copy->{'_macro_recurse'} = \$self_copy->{'_macro_recurse'} || 0;
493             ${indent}${INDENT}my \$max = \$self_copy->{'MAX_MACRO_RECURSE'} || \$Template::Alloy::MAX_MACRO_RECURSE;
494             ${indent}${INDENT}\$self_copy->throw('macro_recurse', \"MAX_MACRO_RECURSE \$max reached\")
495             ${indent}${INDENT}${INDENT}if ++\$self_copy->{'_macro_recurse'} > \$max;
496             ";
497              
498 34         78 foreach my $var (@$args) {
499 28         72 $$str_ref .= "
500             ${indent}${INDENT}\$self_copy->set_variable(";
501 28         82 $$str_ref .= $self->ast_string($var);
502 28         75 $$str_ref .= ", shift(\@_));";
503             }
504 34         251 $$str_ref .= "
505             ${indent}${INDENT}if (\@_ && \$_[-1] && UNIVERSAL::isa(\$_[-1],'HASH')) {
506             ${indent}${INDENT}${INDENT}my \$named = pop \@_;
507             ${indent}${INDENT}${INDENT}foreach my \$name (sort keys %\$named) {
508             ${indent}${INDENT}${INDENT}${INDENT}\$self_copy->set_variable([\$name, 0], \$named->{\$name});
509             ${indent}${INDENT}${INDENT}}
510             ${indent}${INDENT}}
511              
512             ${indent}${INDENT}my \$out = '';
513             ${indent}${INDENT}my \$out_ref = \\\$out;$code
514             ${indent}${INDENT}return \$out;
515             ${indent}};
516             ${indent}\$self->set_variable(".$self->ast_string($name).", \$var);
517             ${indent}};";
518              
519 34         94 return;
520             }
521              
522             sub compile_META {
523 92     92 0 203 my ($self, $node, $str_ref, $indent) = @_;
524 92 100       232 if (my $kp = $node->[3]) {
525 46 50       187 $kp = {@$kp} if ref($kp) eq 'ARRAY';
526 46         213 while (my($key, $val) = each %$kp) {
527 46         161 s/\'/\\\'/g foreach $key, $val;
528 46         249 $self->{'_meta'} .= "\n${indent}'$key' => '$val',";
529             }
530             }
531 92         244 return;
532             }
533              
534             sub compile_NEXT {
535 2     2 0 6 my ($self, $node, $str_ref, $indent) = @_;
536 2   50     8 my $type = $self->{'_in_loop'} || die "Found next while not in FOR, FOREACH or WHILE";
537 2 50       10 $$str_ref .= "\n${indent}(\$var, \$error) = \$loop->get_next;" if $type eq 'FOREACH';
538 2         8 $$str_ref .= "\n${indent}next $type;";
539 2         6 return;
540             }
541              
542             sub compile_PERL{
543 6     6 0 18 my ($self, $node, $str_ref, $indent) = @_;
544              
545             ### fill in any variables
546 6   50     18 my $perl = $node->[4] || return;
547 6         25 my $code = $self->compile_tree($perl, "$indent$INDENT");
548              
549 6         76 $$str_ref .= "
550             ${indent}\$self->throw('perl', 'EVAL_PERL not set') if ! \$self->{'EVAL_PERL'};
551             ${indent}require Template::Alloy::Play;
552             ${indent}\$var = do {
553             ${indent}${INDENT}my \$out = '';
554             ${indent}${INDENT}my \$out_ref = \\\$out;$code
555             ${indent}${INDENT}\$out;
556             ${indent}};
557             ${indent}#\$var = \$1 if \$var =~ /^(.+)\$/s; # blatant untaint
558              
559             ${indent}my \$err;
560             ${indent}eval {
561             ${indent}${INDENT}package Template::Alloy::Perl;
562             ${indent}${INDENT}my \$context = \$self->context;
563             ${indent}${INDENT}my \$stash = \$context->stash;
564             ${indent}${INDENT}local *PERLOUT;
565             ${indent}${INDENT}tie *PERLOUT, 'Template::Alloy::EvalPerlHandle', \$out_ref;
566             ${indent}${INDENT}my \$old_fh = select PERLOUT;
567             ${indent}${INDENT}eval \$var;
568             ${indent}${INDENT}\$err = \$\@;
569             ${indent}${INDENT}select \$old_fh;
570             ${indent}};
571             ${indent}\$err ||= \$\@;
572             ${indent}if (\$err) {
573             ${indent}${INDENT}\$self->throw('undef', \$err) if ! UNIVERSAL::can(\$err, 'type');
574             ${indent}${INDENT}die \$err;
575             ${indent}}";
576              
577 6         15 return;
578             }
579              
580              
581             sub compile_PROCESS {
582 143     143 0 361 my ($self, $node, $str_ref, $indent) = @_;
583 143         419 _compile_defer_to_play($self, $node, $str_ref, $indent);
584             }
585              
586             sub compile_RAWPERL {
587 1     1 0 4 my ($self, $node, $str_ref, $indent) = @_;
588 1         4 _compile_defer_to_play($self, $node, $str_ref, $indent);
589             }
590              
591             sub compile_RETURN {
592 5     5 0 14 my ($self, $node, $str_ref, $indent) = @_;
593              
594 5 50       14 if (defined($node->[3])) {
595 0         0 $$str_ref .= "
596             ${indent}\$var = {return_val => ".$self->compile_expr($node->[3])."};
597             ${indent}\$self->throw('return', \$var);";
598             } else {
599 5         15 $$str_ref .= "
600             ${indent}\$self->throw('return', undef);";
601             }
602             }
603              
604             sub compile_SET {
605 423     423 0 1004 my ($self, $node, $str_ref, $indent) = @_;
606 423         823 my $sets = $node->[3];
607              
608 423         796 my $out = '';
609 423         933 foreach (@$sets) {
610 427         1003 my ($op, $set, $val) = @$_;
611              
612 427 100       1029 if ($self->{'_is_default'}) {
613 3         10 $$str_ref .= "\n${indent}if (! ".$self->compile_expr($set, $indent).") {";
614 3         9 $indent .= $INDENT;
615             }
616 427         1031 $$str_ref .= "\n$indent\$var = ";
617              
618 427 100 66     1514 if (! defined $val) { # not defined
    100          
619 9         19 $$str_ref .= 'undef';
620             } elsif ($node->[4] && $val == $node->[4]) { # a captured directive
621 28         53 my $sub_tree = $node->[4];
622 28 100 66     118 $sub_tree = $sub_tree->[0]->[4] if $sub_tree->[0] && $sub_tree->[0]->[0] eq 'BLOCK';
623 28         101 my $code = $self->compile_tree($sub_tree, "$indent$INDENT");
624 28         132 $$str_ref .= "${indent}do {
625             ${indent}${INDENT}my \$out = '';
626             ${indent}${INDENT}my \$out_ref = \\\$out;$code
627             ${indent}${INDENT}\$out;
628             ${indent}}"
629             } else { # normal var
630 390         936 $$str_ref .= $self->compile_expr($val, $indent);
631             }
632              
633 427 50       1201 if ($Template::Alloy::OP_DISPATCH->{$op}) {
634 0         0 $$str_ref .= ' }';
635             }
636              
637 427         1413 $$str_ref .= ";
638             $indent\$self->set_variable(".$self->ast_string($set).", \$var);";
639              
640 427 100       1236 if ($self->{'_is_default'}) {
641 3         11 substr($indent, -length($INDENT), length($INDENT), '');
642 3         9 $$str_ref .= "\n$indent}";
643             }
644              
645 427         985 $$str_ref .= ";";
646             }
647              
648 423         1032 return $out;
649             }
650              
651             sub compile_STOP {
652 10     10 0 23 my ($self, $node, $str_ref, $indent) = @_;
653 10         32 $$str_ref .= "
654             ${indent}\$self->throw('stop', 'Control Exception');";
655             }
656              
657             sub compile_SWITCH {
658 10     10 0 23 my ($self, $node, $str_ref, $indent) = @_;
659              
660 10         32 $$str_ref .= "
661             ${indent}\$var = ".$self->compile_expr($node->[3], $indent).";";
662              
663 10         20 my $default;
664 10         21 my $i = 0;
665 10         27 while ($node = $node->[5]) { # CASES
666 10 100       31 if (! defined $node->[3]) {
667 3         5 $default = $node;
668 3         8 next;
669             }
670              
671 7         16 $$str_ref .= _node_info($self, $node, $indent);
672 7 100       39 $$str_ref .= "\n$indent" .($i++ ? "} els" : ""). "if (do {
673             ${indent}${INDENT}no warnings;
674             ${indent}${INDENT}my \$var2 = ".$self->compile_expr($node->[3], "$indent$INDENT").";
675             ${indent}${INDENT}scalar grep {\$_ eq \$var} (UNIVERSAL::isa(\$var2, 'ARRAY') ? \@\$var2 : \$var2);
676             ${indent}${INDENT}}) {
677             ${indent}${INDENT}my \$var;";
678              
679 7         27 $$str_ref .= $self->compile_tree($node->[4], "$indent$INDENT");
680             }
681              
682 10 100       22 if ($default) {
683 3         8 $$str_ref .= _node_info($self, $default, $indent);
684 3 50       13 $$str_ref .= "\n$indent" .($i++ ? "} else {" : "if (1) {");
685 3         14 $$str_ref .= $self->compile_tree($default->[4], "$indent$INDENT");
686             }
687              
688 10 100       32 $$str_ref .= "\n$indent}" if $i;
689              
690 10         22 return;
691             }
692              
693             sub compile_THROW {
694 35     35 0 74 my ($self, $node, $str_ref, $indent) = @_;
695              
696 35         60 my ($name, $args) = @{ $node->[3] };
  35         75  
697              
698 35         76 my ($named, @args) = @$args;
699 35 50       79 push @args, $named if ! _is_empty_named_args($named); # add named args back on at end - if there are some
700              
701             $$str_ref .= "
702 35         118 ${indent}\$self->throw(".$self->compile_expr($name, $indent).", [".join(", ", map{$self->compile_expr($_, $indent)} @args)."]);";
  31         67  
703 35         109 return;
704             }
705              
706              
707             sub compile_TRY {
708 50     50 0 135 my ($self, $node, $str_ref, $indent) = @_;
709              
710 50         279 $$str_ref .= "
711             ${indent}do {
712             ${indent}my \$out = '';
713             ${indent}eval {
714             ${indent}${INDENT}my \$out_ref = \\\$out;"
715             . $self->compile_tree($node->[4], "$indent$INDENT") ."
716             ${indent}};
717             ${indent}my \$err = \$\@;
718             ${indent}\$\$out_ref .= \$out;
719             ${indent}if (\$err) {";
720              
721 50         110 my $final;
722 50         96 my $i = 0;
723 50         82 my $catches_str = '';
724 50         80 my @names;
725 50         166 while ($node = $node->[5]) { # CATCHES
726 48 100       131 if ($node->[0] eq 'FINAL') {
727 3         7 $final = $node;
728 3         7 next;
729             }
730 45         155 $catches_str .= _node_info($self, $node, "$indent$INDENT");
731 45         178 $catches_str .= "\n${indent}${INDENT}} elsif (\$index == ".(scalar @names).") {";
732 45         170 $catches_str .= $self->compile_tree($node->[4], "$indent$INDENT$INDENT");
733 45         168 push @names, $node->[3];
734             }
735 50 100       131 if (@names) {
736 44         225 $$str_ref .= "
737             ${indent}${INDENT}\$err = \$self->exception('undef', \$err) if ! UNIVERSAL::can(\$err, 'type');
738             ${indent}${INDENT}my \$type = \$err->type;
739             ${indent}${INDENT}die \$err if \$type =~ /stop|return/;
740             ${indent}${INDENT}local \$self->{'_vars'}->{'error'} = \$err;
741             ${indent}${INDENT}local \$self->{'_vars'}->{'e'} = \$err;
742              
743             ${indent}${INDENT}my \$index;
744             ${indent}${INDENT}my \@names = (";
745 44         82 $i = 0;
746 44         138 foreach $i (0 .. $#names) {
747 45 100       135 if (defined $names[$i]) {
748 8         35 $$str_ref .= "\n${indent}${INDENT}${INDENT}scalar(".$self->compile_expr($names[$i], "$indent$INDENT$INDENT")."), # $i;";
749             } else {
750 37         142 $$str_ref .= "\n${indent}${INDENT}${INDENT}undef, # $i";
751             }
752             }
753 44         286 $$str_ref .= "
754             ${indent}${INDENT});
755             ${indent}${INDENT}for my \$i (0 .. \$#names) {
756             ${indent}${INDENT}${INDENT}my \$name = (! defined(\$names[\$i]) || lc(\$names[\$i]) eq 'default') ? '' : \$names[\$i];
757             ${indent}${INDENT}${INDENT}\$index = \$i if \$type =~ m{^ \\Q\$name\\E \\b}x && (! defined(\$index) || length(\$names[\$index]) < length(\$name));
758             ${indent}${INDENT}}
759             ${indent}${INDENT}if (! defined \$index) {
760             ${indent}${INDENT}${INDENT}die \$err;"
761             .$catches_str."
762             ${indent}${INDENT}}";
763              
764             } else {
765 6         19 $$str_ref .= "
766             ${indent}\$self->throw('throw', 'Missing CATCH block');";
767             }
768 50         121 $$str_ref .= "
769             ${indent}}";
770 50 100       173 if ($final) {
771 3         11 $$str_ref .= _node_info($self, $final, $indent);
772 3         10 $$str_ref .= $self->compile_tree($final->[4], "$indent");
773             }
774 50         123 $$str_ref .="
775             ${indent}};";
776              
777 50         127 return;
778             }
779              
780 8     8 0 25 sub compile_UNLESS { $DIRECTIVES->{'IF'}->(@_) }
781              
782             sub compile_USE {
783 43     43 0 153 my ($self, $node, $str_ref, $indent) = @_;
784 43         156 _compile_defer_to_play($self, $node, $str_ref, $indent);
785             }
786              
787             sub compile_VIEW {
788 28     28 0 94 my ($self, $node, $str_ref, $indent) = @_;
789 28         58 my ($blocks, $args, $name) = @{ $node->[3] };
  28         164  
790              
791 28         122 my $_name = $self->ast_string($name);
792              
793             # [[undef, '{}', 'key1', 'val1', 'key2', 'val2'], 0]
794 28         92 $args = $args->[0];
795 28         157 $$str_ref .= "
796             ${indent}do {
797             ${indent}${INDENT}my \$name = $_name;
798             ${indent}${INDENT}my \$hash = {};";
799 28         123 foreach (my $i = 2; $i < @$args; $i+=2) {
800 35         135 $$str_ref .= "
801             ${indent}${INDENT}\$var = ".$self->compile_expr($args->[$i+1], $indent).";
802             ${indent}${INDENT}";
803 35         108 my $key = $args->[$i];
804 35 50       89 if (ref $key) {
805 0 0 0     0 if (@$key == 2 && ! ref($key->[0]) && ! $key->[1]) {
      0        
806 0         0 $key = $key->[0];
807             } else {
808 0         0 $$str_ref .= "
809             ${indent}${INDENT}\$self->set_variable(".$self->compile_expr($key, $indent).", \$var);";
810 0         0 next;
811             }
812             }
813 35         73 $key =~ s/([\'\\])/\\$1/g;
814 35         127 $$str_ref .= "\$hash->{'$key'} = \$var;";
815             }
816              
817 28         121 $$str_ref .= "
818             ${indent}${INDENT}my \$prefix = \$hash->{'prefix'} || (ref(\$name) && \@\$name == 2 && ! \$name->[1] && ! ref(\$name->[0])) ? \"\$name->[0]/\" : '';
819             ${indent}${INDENT}my \$blocks = \$hash->{'blocks'} = {};";
820 28         143 foreach my $key (keys %$blocks) {
821 19         94 my $code = $self->compile_tree($blocks->{$key}, "$indent$INDENT$INDENT$INDENT");
822 19         56 $key =~ s/([\'\\])/\\$1/g;
823 19         150 $$str_ref .= "
824             ${indent}${INDENT}\$blocks->{'$key'} = {
825             ${indent}${INDENT}${INDENT}name => \$prefix . '$key',
826             ${indent}${INDENT}${INDENT}_perl => {code => sub {
827             ${indent}${INDENT}${INDENT}${INDENT}my (\$self, \$out_ref, \$var) = \@_;$code
828              
829             ${indent}${INDENT}${INDENT}${INDENT}return 1;
830             ${indent}${INDENT}${INDENT}} },
831             ${indent}${INDENT}};";
832             }
833              
834 28         201 $$str_ref .= "
835             ${indent}${INDENT}\$self->throw('view', 'Could not load Template::View library')
836             ${indent}${INDENT}${INDENT} if ! eval { require Template::View };
837             ${indent}${INDENT}my \$view = Template::View->new(\$self->context, \$hash)
838             ${indent}${INDENT}${INDENT}|| \$self->throw('view', \$Template::View::ERROR);
839             ${indent}${INDENT}my \$old_view = \$self->play_expr(['view', 0]);
840             ${indent}${INDENT}\$self->set_variable(\$name, \$view);
841             ${indent}${INDENT}\$self->set_variable(['view', 0], \$view);";
842              
843 28 50       107 if ($node->[4]) {
844 28         153 $$str_ref .= "
845             ${indent}${INDENT}my \$out = '';
846             ${indent}${INDENT}my \$out_ref = \\\$out;"
847             .$self->compile_tree($node->[4], "$indent$INDENT");
848             }
849              
850 28         137 $$str_ref .= "
851             ${indent}${INDENT}\$self->set_variable(['view', 0], \$old_view);
852             ${indent}${INDENT}\$view->seal;
853             ${indent}};";
854              
855              
856 28         73 return;
857             }
858              
859             sub compile_WHILE {
860 13     13 0 38 my ($self, $node, $str_ref, $indent) = @_;
861              
862 13         37 local $self->{'_in_loop'} = 'WHILE';
863 13         47 my $code = $self->compile_tree($node->[4], "$indent$INDENT");
864              
865 13         50 $$str_ref .= "
866             ${indent}my \$count = \$Template::Alloy::WHILE_MAX;
867             ${indent}WHILE: while (--\$count > 0) {
868             ${indent}my \$var = ".$self->compile_expr($node->[3], $indent).";
869             ${indent}last if ! \$var;$code
870             ${indent}}";
871 13         49 return;
872             }
873              
874             sub compile_WRAPPER {
875 9     9 0 25 my ($self, $node, $str_ref, $indent) = @_;
876              
877 9         16 my ($named, @files) = @{ $node->[3] };
  9         25  
878 9         27 $named = $self->ast_string($named);
879              
880             $$str_ref .= "
881             ${indent}\$var = do {
882             ${indent}${INDENT}my \$out = '';
883             ${indent}${INDENT}my \$out_ref = \\\$out;"
884             .$self->compile_tree($node->[4], "$indent$INDENT")."
885             ${indent}${INDENT}\$out;
886             ${indent}};
887             ${indent}for my \$file (reverse("
888 9         50 .join(",${indent}${INDENT}", map {"\$self->play_expr(".$self->ast_string($_).")"} @files).")) {
  9         27  
889             ${indent}${INDENT}local \$self->{'_vars'}->{'content'} = \$var;
890             ${indent}${INDENT}\$var = '';
891             ${indent}${INDENT}require Template::Alloy::Play;
892             ${indent}\$Template::Alloy::Play::DIRECTIVES->{'INCLUDE'}->(\$self, [$named, \$file], ['$node->[0]', $node->[1], $node->[2]], \\\$var);
893             ${indent}}
894             ${indent}\$\$out_ref .= \$var if defined \$var;";
895              
896 9         37 return;
897             }
898              
899              
900             ###----------------------------------------------------------------###
901              
902             1;
903              
904             __END__