File Coverage

blib/lib/HTML/Template/Compiled/Compiler.pm
Criterion Covered Total %
statement 640 679 94.2
branch 283 338 83.7
condition 81 93 87.1
subroutine 67 69 97.1
pod 0 15 0.0
total 1071 1194 89.7


line stmt bran cond sub pod time code
1             package HTML::Template::Compiled::Compiler;
2 50     50   211 use strict;
  50         56  
  50         1569  
3 50     50   146 use warnings;
  50         44  
  50         1570  
4 48     48   791 use Data::Dumper;
  48         370  
  48         3178  
5 48     48   180 use Carp qw(croak carp);
  48         52  
  48         1965  
6 48     48   164 use HTML::Template::Compiled::Expression qw(:expressions);
  48         46  
  48         5076  
7 47     47   180 use HTML::Template::Compiled::Utils qw(:walkpath);
  47         51  
  47         4534  
8 46     46   191 use File::Basename qw(dirname);
  46         60  
  46         2507  
9              
10             our $VERSION = '1.003'; # VERSION
11              
12             our $DISABLE_NEW_ALIAS = 0;
13              
14 46     46   160 use Carp qw(croak carp);
  46         58  
  46         1990  
15 45     45   148 use constant D => 0;
  45         49  
  45         2740  
16              
17 39     39   129 use constant T_VAR => 'VAR';
  39         48  
  39         1459  
18 39     39   128 use constant T_IF => 'IF';
  39         50  
  39         1444  
19 39     39   135 use constant T_UNLESS => 'UNLESS';
  39         44  
  39         1494  
20 39     39   126 use constant T_ELSIF => 'ELSIF';
  39         46  
  39         1360  
21 39     39   121 use constant T_ELSE => 'ELSE';
  39         45  
  39         1339  
22 39     39   118 use constant T_IF_DEFINED => 'IF_DEFINED';
  39         36  
  39         1492  
23 39     39   117 use constant T_END => '__EOT__';
  39         47  
  39         1336  
24 39     39   124 use constant T_WITH => 'WITH';
  39         42  
  39         1274  
25 39     39   125 use constant T_SWITCH => 'SWITCH';
  39         37  
  39         1532  
26 39     39   118 use constant T_CASE => 'CASE';
  39         40  
  39         1502  
27 39     39   117 use constant T_INCLUDE => 'INCLUDE';
  39         36  
  39         1315  
28 39     39   116 use constant T_LOOP => 'LOOP';
  39         300  
  39         1659  
29 39     39   132 use constant T_WHILE => 'WHILE';
  39         37  
  39         1312  
30 39     39   118 use constant T_EACH => 'EACH';
  39         38  
  39         1888  
31 39     39   116 use constant T_INCLUDE_VAR => 'INCLUDE_VAR';
  39         43  
  39         1589  
32 39     39   135 use constant T_INCLUDE_STRING => 'INCLUDE_STRING';
  39         37  
  39         1397  
33 39     39   115 use constant T_USE_VARS => 'USE_VARS';
  39         34  
  39         1366  
34 39     39   118 use constant T_SET_VAR => 'SET_VAR';
  39         38  
  39         1612  
35 38     38   125 use constant T_WRAPPER => 'WRAPPER';
  38         33  
  38         1313  
36              
37 38     38   116 use constant INDENT => ' ';
  38         63  
  38         1304  
38              
39 38     38   117 use constant NO_TAG => 0;
  38         43  
  38         1281  
40 36     36   117 use constant OPENING_TAG => 1;
  36         32  
  36         1221  
41 36     36   116 use constant CLOSING_TAG => 2;
  36         527  
  36         1226  
42              
43 36     36   115 use constant ATTR_ESCAPES => 0;
  36         39  
  36         1147  
44 36     36   103 use constant ATTR_TAGS => 1;
  36         32  
  36         1113  
45 36     36   106 use constant ATTR_NAME_RE => 2;
  36         35  
  36         78643  
46              
47 131     131 0 525 sub set_escapes { $_[0]->[ATTR_ESCAPES] = $_[1] }
48 17     17 0 27 sub get_escapes { $_[0]->[ATTR_ESCAPES] }
49 0     0 0 0 sub set_tags { $_[0]->[ATTR_TAGS] = $_[1] }
50             sub add_tags {
51 3     3 0 3 for my $key (keys %{ $_[1] }) {
  3         7  
52 3         11 $_[0]->[ATTR_TAGS]->{$key} = $_[1]->{$key};
53             }
54             }
55 151     151 0 185 sub get_tags { $_[0]->[ATTR_TAGS] }
56 151     151 0 531 sub set_name_re { $_[0]->[ATTR_NAME_RE] = $_[1] }
57 336     336 0 390 sub get_name_re { $_[0]->[ATTR_NAME_RE] }
58              
59             our %ESCAPES;
60              
61             sub delete_subs {
62             # delete all userdefined subs
63 0     0 0 0 %ESCAPES = ();
64             }
65              
66             sub setup_escapes {
67 6     6 0 10 my ($class, $plug_class, $escapes) = @_;
68 6         20 for my $key (keys %$escapes) {
69 4         5 my $def = $escapes->{$key};
70 4         5 my $sub;
71 4 50       8 if (ref $def eq 'HASH') {
72 0         0 $sub = $def->{code};
73 0 0       0 if (my $arguments = $def->{arguments} ) {
74 0         0 $ESCAPES{ $plug_class }->{ $key }->{arguments} = $arguments;
75             }
76             }
77             else {
78 4         5 $sub = $def;
79             }
80 4 100       15 if (ref $sub eq 'CODE') {
81 3         15 $ESCAPES{ $plug_class }->{ $key }->{code} = $sub;
82             }
83             else {
84 1         1 $ESCAPES{ $plug_class }->{ $key }->{code} = \&{ $sub };
  1         4  
85             }
86             }
87             }
88              
89             sub add_escapes {
90 3     3 0 4 my ($self, $plug_class, $new_escapes) = @_;
91 3         6 my $escapes = $self->get_escapes;
92 3         7 for my $key (keys %$new_escapes) {
93 4         12 $escapes->{ $key } = $plug_class;
94             }
95             }
96              
97             sub new {
98 131     131 0 184 my $class = shift;
99 131         193 my $self = [];
100 131         177 bless $self, $class;
101 131         312 $self->set_escapes({});
102 131         256 return $self;
103             }
104              
105             sub _escape_expression {
106 14     14   24 my ( $self, $exp, $escape ) = @_;
107 14 50       26 return $exp unless $escape;
108 14         38 my @escapes = split m/\|/, uc $escape;
109 14         29 my $escapes = $self->get_escapes();
110 14         22 for (@escapes) {
111 15 100       87 if ( $_ eq 'HTML' ) {
    100          
    100          
    100          
    100          
    100          
    50          
112 2         8 $exp =
113             _expr_function( 'HTML::Template::Compiled::Utils::escape_html',
114             $exp, );
115             }
116             elsif ( $_ eq 'HTML_ALL' ) {
117 1         3 $exp =
118             _expr_function( 'HTML::Template::Compiled::Utils::escape_html_all',
119             $exp, );
120             }
121             elsif ( $_ eq 'URL' ) {
122 4         14 $exp =
123             _expr_function( 'HTML::Template::Compiled::Utils::escape_uri',
124             $exp, );
125             }
126             elsif ( $_ eq 'JS' ) {
127 2         7 $exp =
128             _expr_function( 'HTML::Template::Compiled::Utils::escape_js',
129             $exp, );
130             }
131             elsif ( $_ eq 'IJSON' ) {
132 1         4 $exp =
133             _expr_function( 'HTML::Template::Compiled::Utils::escape_ijson',
134             $exp, );
135             }
136             elsif ( $_ eq 'DUMP' ) {
137 1         5 $exp = _expr_method( 'dump', _expr_literal('$t'), $exp, );
138             }
139             elsif (my $plug_class = $escapes->{$_}) {
140 4         9 my $subref = "\$HTML::Template::Compiled::Compiler::ESCAPES\{'$plug_class'\}->\{'$_'\}->\{code\}";
141 4         6 my @args = $exp;
142 4 50       12 if (my $arguments = $ESCAPES{ $plug_class }->{ $_ }->{arguments}) {
143 0         0 @args = ();
144 0         0 for my $arg (@$arguments) {
145 0 0       0 if ($arg eq 'var') {
    0          
146 0         0 push @args, $exp;
147             }
148             elsif ($arg eq 'self') {
149 0         0 push @args, "\$t->get_plugin('$plug_class')";
150             #push @args, 23;
151             }
152             }
153             }
154 4         27 $exp = HTML::Template::Compiled::Expression::SubrefCall->new( $subref, @args );
155             }
156             }
157 14 50       57 return ref $exp ? $exp->to_string : $exp;
158             }
159              
160             sub init_name_re {
161 151     151 0 383 my ($self, %args) = @_;
162 151         1470 my $re = qr#
163             \Q$args{deref}\E |
164             \Q$args{method_call}\E |
165             \Q$args{formatter_path}\E
166             #x;
167 151         325 $self->set_name_re($re);
168             }
169              
170             my %loop_context = (
171             __index__ => '$__ix__',
172             __counter__ => '$__ix__+1',
173             __first__ => '$__ix__ == $[',
174             __last__ => '$__ix__ == $__size__',
175             __odd__ => '!($__ix__ & 1)',
176             __even__ => '($__ix__ & 1)',
177             __inner__ => '$__ix__ != $[ && $__ix__ != $__size__',
178             __outer__ => '$__ix__ == $[ || $__ix__ == $__size__',
179             __key__ => '$__key__',
180             __value__ => '$__value__',
181             __break__ => '$__break__',
182             __filename__ => '$t->get_file',
183             __filenameshort__ => '$t->get_filename',
184             __wrapped__ => '$args->{wrapped}',
185             );
186              
187             sub parse_var {
188 368     368 0 1573 my ( $self, $t, %args ) = @_;
189 368         396 my $lexicals = $args{lexicals};
190 368         297 my $context = $args{context};
191             # calling context. 'list' or empty (which means scalar)
192 368   100     1123 my $ccontext = $args{ccontext} || '';
193              
194              
195 368 100 66     795 if (!defined $args{var} and defined $args{expr}) {
196 27         28 my $compiler = $args{compiler};
197             return HTML::Template::Compiled::Expr->parse_expr(
198             $compiler,
199             $t,
200             %args,
201             expr => $args{expr},
202 27         118 context => $context,
203             );
204             }
205              
206              
207 341 50       888 if (!$t->validate_var($args{var})) {
208             $t->get_parser->_error_wrong_tag_syntax(
209             {
210             fname => $context->get_file,
211             line => $context->get_line,
212             token => "",
213             },
214             $args{var},
215              
216 0         0 );
217             }
218 341 100       737 if ( grep { defined $_ && $args{var} eq $_ } @$lexicals ) {
  129 100       419  
219 5         9 my $varstr = "\$HTML::Template::Compiled::_lexi_$args{var}";
220 5         14 return $varstr;
221             }
222 336         651 my $lexi = join '|', grep defined, @$lexicals;
223 336         371 my $varname = '$var';
224 336         599 my $re = $self->get_name_re;
225             # warn __PACKAGE__.':'.__LINE__.": re: $re\n";
226             #warn __PACKAGE__.':'.__LINE__.": ========== ($args{var})\n";
227 336         263 my $root = 0;
228 336         271 my $up_stack = 0;
229 336         257 my $initial_var = '$$C';
230 336         237 my $is_object_var = '$C_IS_OBJECT';
231 336         258 my $root_hash = 0;
232 336         937 my $OPT_INITIAL_VAR = $t->get_optimize->{initial_var};
233 336         778 my $OPT_IS_OBJECT = $t->get_optimize->{object_check};
234 336         631 my $OPT_ROOT_HASH = $t->get_optimize->{root_hash};
235 336 50       476 my $use_initial_var = $OPT_INITIAL_VAR ? 1 : 0;
236 336 100 100     622 if ( $t->get_loop_context && $args{var} =~ m/^__(\w+)__$/ ) {
237 54 50       133 if (exists $loop_context{ lc $args{var} }) {
238 54         75 my $lc = $loop_context{ lc $args{var} };
239 54         155 return $lc;
240             }
241             }
242             # explicitly use aliases with '$' at the beginning
243 282 100 100     3996 if (not $DISABLE_NEW_ALIAS and $args{var} =~ s/^\$(\w+)//) {
    100 100        
    100 100        
    100          
244 9         20 $initial_var = "\$HTML::Template::Compiled::_lexi_$1";
245 9         8 $is_object_var = '';
246             }
247             elsif ($lexi and $args{var} =~ s/^($lexi)($re)/$2/) {
248 2         4 $initial_var = "\$HTML::Template::Compiled::_lexi_$1";
249 2         1 $is_object_var = '';
250             }
251             elsif ( $args{var} =~ m/^_/ && $args{var} !~ m/^__(\w+)__$/ ) {
252 16         43 $args{var} =~ s/^_//;
253 16         21 $root = 0;
254 16         21 $is_object_var = '';
255             }
256             elsif ( my @roots = $args{var} =~ m/\G($re)/gc) {
257             #print STDERR "ROOTS: (@roots)\n";
258 35 100       92 $root = 1 if @roots == 1;
259 35         319 $args{var} =~ s/^($re)+//;
260 35 100       126 if (@roots > 1) {
    50          
261 1 50       3 croak "Cannot navigate up the stack" if !$t->get_global_vars & 2;
262 1         2 $up_stack = $#roots;
263 1         2 $initial_var = "\$t->get_globalstack->[-$up_stack]";
264 1         1 $use_initial_var = 0;
265 1         2 $is_object_var = '';
266             }
267             elsif (@roots == 1) {
268 34         44 $initial_var = '$P';
269 34         32 $is_object_var = '$P_IS_OBJECT';
270 34 50       71 $root_hash = 1 if $OPT_ROOT_HASH;
271             }
272             }
273 282         1696 my @split = split m/(?=$re)/, $args{var};
274             @split = map {
275 282         383 my @ret;
  306         240  
276 306         264 my $count = 0;
277 306 100       613 if (s/#\z//) {
278 4         4 $count = 1;
279             }
280 306 100       510 if ( m/(.*)\[(-?\d+)\]/ ) {
281 15         47 my @slice = "[$2]";
282 15         29 my $var = "$1";
283 15         51 while ($var =~ s/\[(-?\d+)\]\z//) {
284 1         4 unshift @slice, "[$1]";
285             }
286 15         33 @ret = ($var, @slice)
287             }
288             else {
289 291         442 @ret = $_
290             }
291 306 100       572 push @ret, '#' if $count;
292 306         706 @ret;
293             } @split;
294 282         264 my @paths;
295             #print STDERR "paths: (@split)\n";
296 282         275 my $count = 0;
297 282         648 my $use_objects = $t->get_objects;
298 282 100       476 my $strict = $use_objects eq 'strict' ? 1 : 0;
299 282         340 my $method_args = '';
300 282         225 my $varstr = '';
301             @split = map {
302 282         273 s#\\#\\\\#g;
  326         337  
303 326         274 s#'#\\'#g;
304 326 100       743 length $_ ? $_ : ()
305             } @split;
306 282 100       540 if (@split == 1) {
307 223         215 $varname = $initial_var;
308             }
309 282         261 my $used_initial_var = 0;
310 282         691 for my $i (0 .. $#split) {
311 322 100 100     1123 if ($i == $#split and defined $args{method_args}) {
312 1         2 $method_args = $args{method_args};
313             }
314 322         567 my $around = ['', ''];
315 322 100 100     1026 if ($i == $#split and $ccontext eq 'list') {
316 2 100       15 if ($context->get_name eq 'EACH') {
    50          
317 1         2 $around = ['+{', '}'];
318             }
319             elsif ($context->get_name eq 'LOOP') {
320 1         2 $around = ['[', ']'];
321             }
322             }
323 322         369 my $p = $split[$i];
324             #warn __PACKAGE__.':'.__LINE__.": path: $p\n";
325 322         258 my $copy = $p;
326 322         257 my $array_index;
327             my $get_length;
328 0         0 my $method_call;
329 0         0 my $deref;
330 0         0 my $formatter_call;
331 0         0 my $guess;
332 0         0 my $try_global;
333 322 100 66     3141 if ( $p =~ s/^\[(-?\d+)\]$/$1/ ) {
    100          
    100          
    100          
    100          
334             # array index
335 16         25 $array_index = $1;
336             }
337             elsif ( $p =~ s/^#$// ) {
338             # number of elements
339 4         4 $get_length = 1;
340             }
341             elsif ( $use_objects and $p =~ s/^\Q$args{method_call}// ) {
342             # maybe method call
343 35         38 $method_call = 1;
344             }
345             elsif ( $p =~ s/^\Q$args{deref}// ) {
346             # deref
347 10         14 $deref = 1;
348             }
349             elsif ( $p =~ s/^\Q$args{formatter_path}// ) {
350 3         3 $formatter_call = 1;
351             }
352             else {
353             # guess
354 254         263 $guess = 1;
355             }
356 322 100 100     1039 if ($method_call || $guess) {
357 289 100       1017 unless ($p =~ m/^[A-Za-z_][A-Za-z0-9_]*\z/) {
358             # not a valid method name
359 2         3 $deref = 1;
360 2         2 $method_call = $guess = 0;
361             }
362             }
363 322 100 100     1165 if ($method_call || $guess || $deref) {
      100        
364 299 100 100     962 if ($count == 0 && $t->get_global_vars & 1) {
365 23         19 $try_global = 1;
366 23         20 $method_call = $guess = $deref = 0;
367             }
368             }
369              
370 322 100       673 my $path = $t->get_case_sensitive ? $p : lc $p;
371 322         270 my $code;
372 322 100 100     1364 if ( defined $array_index ) {
    100          
    100          
    100          
    100          
    50          
373             # array index
374 16         28 $code = "$varname\->[$array_index]";
375             }
376              
377             elsif ( $get_length ) {
378             # number of elements
379 4         5 $code = "scalar \@{$varname || []}";
380             }
381              
382             elsif ($try_global) {
383 23         44 $code = "\$t->try_global($varname, '$path')";
384             }
385              
386             elsif ( $method_call || $guess) {
387             # maybe method call
388 264         404 my $check_object = "UNIVERSAL::can($varname,'can')";
389 264         240 my $local_varname = $varname;
390 264 100       438 if ($i == 0) {
391 236 100       360 if ($use_initial_var) {
392 235         201 $local_varname = $initial_var;
393 235         190 $used_initial_var = 1;
394 235         318 $check_object = "UNIVERSAL::can($local_varname,'can')";
395             }
396 236 50 33     469 if ($OPT_IS_OBJECT and $is_object_var) {
397 0         0 $check_object = $is_object_var;
398             }
399              
400             }
401 264 50 66     901 if ($i == 0 and $root_hash) {
    100          
402 0         0 $code = "$local_varname\->\{'$path'\}";
403             }
404             elsif ($strict) {
405 261         732 $code = "($check_object ? $local_varname->$p($method_args) : $local_varname\->\{'$path'\})";
406             }
407             else {
408 3         8 $code = "(Scalar::Util::blessed($local_varname) ? $local_varname->can('$p') ? $local_varname->$p($method_args) : undef : $local_varname\->\{'$path'\})";
409             }
410             }
411              
412             elsif ( $deref ) {
413 12         26 $code = "$varname\->\{'$path'\}";
414             }
415              
416             elsif ( $formatter_call ) {
417 3         5 $code = "\$t->_walk_formatter($varname, '$p', @{[$t->get_global_vars]})";
  3         5  
418             }
419 322         511 $code = $around->[0] . $code . $around->[1];
420 322 100       491 if (0 or @split > 1) {
421 99 100 100     289 if ($used_initial_var and $i==0) {
422 31         84 $varstr .= "my $varname = $code;";
423             }
424             else {
425 68         137 $varstr .= "$varname = $code;";
426             }
427             }
428             else {
429 223         228 $varstr = $code;
430             }
431              
432 322         698 $count++;
433             }
434             #my $final = $context->get_name eq 'VAR' ? 1 : 0;
435 282 100       396 if (0 or @split > 1) {
436 42 100       67 if ($used_initial_var) {
437 31         78 $varstr = "do { $varstr $varname }";
438             }
439             else {
440 11         26 $varstr = "do { my $varname = $initial_var; $varstr $varname }";
441             }
442             }
443             else {
444 240 100       385 $varstr = $initial_var unless length $varstr;
445 240         250 $varstr = "$varstr";
446             }
447 282         1023 return $varstr;
448             }
449              
450             sub dump_string {
451 322     322 0 361 my ($self, $string) = @_;
452 322         926 my $dump = HTML::Template::Compiled->dump_var($string, 'string');
453 322 50       29831 $dump =~ s#^\$string *= *## or die "dump_string() failed";
454 322         814 $dump =~ s/;$//;
455 322         1394 return $dump;
456             }
457              
458             sub compile {
459 161     161 0 231 my ( $class, $self, $text, $fname ) = @_;
460 161         140 D && $self->log("compile($fname)");
461 161 100       422 if ( my $filter = $self->get_filter ) {
462 7         149 require HTML::Template::Compiled::Filter;
463 7         23 $filter->filter($text);
464             }
465 161         364 my $parser = $self->get_parser;
466 161         520 my @p = $parser->parse($fname, $text);
467 151 100       638 if (my $df = $self->get_debug->{file}) {
468 6 100       24 my $debugfile = $df =~ m/short/ ? $self->get_filename : $self->get_file;
469 6 100       14 if ($df =~ m/start/) {
470 4         13 unshift @p,
471             HTML::Template::Compiled::Token::Text->new([
472             '', 0,
473             undef, undef, undef, $self->get_file, 0
474             ]);
475             }
476 6 100       15 if ($df =~ m/end/) {
477 4         11 push @p,
478             HTML::Template::Compiled::Token::Text->new([
479             '', 0,
480             undef, undef, undef, $self->get_file, 0
481             ]);
482             }
483             }
484 151         200 my $code = '';
485 151         289 my $info = {}; # for query()
486 151         213 my $info_stack = [$info];
487              
488 151         309 my $test = $self->get_debug->{options};
489             # got this trick from perlmonks.org
490             my $anon = D
491 151 50       336 || ($self->get_debug->{options} & HTML::Template::Compiled::DEBUG_COMPILED()) ? qq{local *__ANON__ = "htc_$fname";\n} : '';
492              
493 36     36   196 no warnings 'uninitialized';
  36         69  
  36         120122  
494 151         177 my $string_output = '$OUT .= ';
495 151         246 my $fh_output = 'print $OFH ';
496 151         139 my $output = $string_output;
497 151         346 my $out_fh = $self->get_out_fh;
498 151 100       300 if ($out_fh) {
499 7         8 $output = $fh_output;
500             }
501 151         221 my @outputs = ($output);
502 151         150 my $warnings_string = "no warnings;\n";
503 151 100       388 if (my $warnings = $self->get_warnings) {
504 4 100       13 if ($warnings eq 1) {
    50          
505 2         3 $warnings_string = "use warnings;\n";
506             }
507             elsif ($warnings eq 'fatal') {
508 2         4 $warnings_string = "use warnings FATAL => qw(all);\n";
509             }
510             }
511 151         505 my $OPT_IS_OBJECT = $self->get_optimize->{object_check};
512 151         264 my $OPT_ROOT_HASH = $self->get_optimize->{root_hash};
513 151         365 my $header = <<"EOM";
514             sub {
515             use vars qw/ \$__ix__ \$__key__ \$__value__ \$__break__ \$__size__ /;
516             use strict;
517             $warnings_string
518             $anon
519             my (\$t, \$P, \$C, \$OFH, \$args) = \@_;
520             my \$OUT = '';
521             EOM
522 151 50       271 if ($OPT_IS_OBJECT) {
523 0 0       0 if ($OPT_ROOT_HASH) {
524 0         0 $header .= <<"EOM";
525             my \$P_IS_OBJECT = 1;
526             EOM
527             }
528             else {
529 0         0 $header .= <<"EOM";
530             my \$P_IS_OBJECT = UNIVERSAL::can(\$P, 'can');
531             EOM
532             }
533 0         0 $header .= <<"EOM";
534             my \$C_IS_OBJECT = UNIVERSAL::can(\$\$C, 'can');
535             EOM
536             }
537              
538 151         138 my @lexicals;
539             my @switches;
540 151         328 my $tags = $class->get_tags;
541 151         396 my $meth = $self->method_call;
542 151         342 my $deref = $self->deref;
543 151         364 my $format = $self->formatter_path;
544 151         390 $class->init_name_re(
545             deref => $deref,
546             method_call => $meth,
547             formatter_path => $format,
548             );
549 151         449 my %var_args = (
550             deref => $deref,
551             method_call => $meth,
552             formatter_path => $format,
553             lexicals => \@lexicals,
554             );
555 151         174 my %use_vars;
556             my @wrapped;
557 151         137 my $globalstack = '';
558 151 100       455 if ($self->get_global_vars) {
559 8         10 $globalstack = '$new->set_globalstack($t->get_globalstack);';
560             }
561 151         321 my $line_info = $self->get_line_info;
562 151         338 for my $token (@p) {
563 1026 100       1903 @use_vars{ @lexicals } = () if @lexicals;
564 1026         2429 my ($text, $line, $open_close, $tname, $attr, $f, $nlevel) = @$token;
565             #print STDERR "tags: ($text, $line, $open_close, $tname, $attr)\n";
566             #print STDERR "p: '$text'\n";
567 1026         1415 my $indent = INDENT x $nlevel;
568 1026 100       1359 $code .= "#line $line $fname\n" if $line_info;
569 1026 100       2449 if (!$token->is_tag) {
    100          
    50          
570 544 100       817 if ( length $text ) {
571             # don't ask me about this line. i tried to get HTC
572             # running with utf8 (directly in the template),
573             # and without this line i only got invalid characters.
574 541         632 local $Data::Dumper::Deparse = 1;
575              
576 541 100       1646 if ($text =~ m/\A(?:\r?\n|\r)\z/) {
577 223         248 $text =~ s/\r/\\r/;
578 223         400 $text =~ s/\n/\\n/;
579 223         725 $code .= qq#$indent$output "$text";# . $/;
580             }
581             else {
582 318         710 $code .= qq#$indent$output # . $class->dump_string($text) . ';' . $/;
583             }
584             }
585             }
586             elsif ($token->is_open) {
587             # --------- TMPL_VAR
588 383 100       828 if ($tname eq T_VAR) {
    100          
    100          
589 235         326 my $var = $attr->{NAME};
590 235 100       519 if ($self->get_use_query) {
591 28         68 $info_stack->[-1]->{lc $var}->{type} = T_VAR;
592             }
593 235         214 my $expr;
594 235 50 33     682 if (exists $tags->{$tname} && exists $tags->{$tname}->{open}) {
595 0         0 $expr = $tags->{$tname}->{open}->($class, $self, {
596             %var_args,
597             context => $token,
598             },);
599             }
600             else {
601 235         1205 $expr = $class->_compile_OPEN_VAR($self, {
602             %var_args,
603             context => $token,
604             },);
605             }
606 235         871 $code .= qq#${indent}$output #
607             . $expr . qq#;\n#;
608             }
609              
610             # ---------- TMPL_PERL
611             elsif ($tname eq 'PERL') {
612 4         5 my $perl = $attr->{PERL};
613 4         15 my %map = (
614             __HTC__ => '$t',
615             __ROOT__ => '$P',
616             __CURRENT__ => '$$C',
617             __OUT__ => $output,
618             __INDEX__ => '$__ix__',
619             );
620 4         13 my $re = join '|', keys %map;
621 4 50       138 $perl =~ s/($re)/exists $map{$1} ? $map{$1} : $1/eg;
  9         31  
622 4         16 $code .= $perl;
623             }
624              
625             # --------- TMPL_WITH
626             elsif ($tname eq T_WITH) {
627 13         24 my $var = $attr->{NAME};
628             my $varstr = $class->parse_var($self,
629             %var_args,
630             var => $var,
631             context => $token,
632             compiler => $class,
633             expr => $attr->{EXPR},
634 13         57 );
635 13         33 $code .= <<"EOM";
636             ${indent}\{
637             EOM
638 13 100       726 if ($self->get_global_vars) {
639 5         15 $code .= _expr_method(
640             'pushGlobalstack',
641             '$t', '$$C'
642             )->to_string($nlevel) . ";\n";
643             }
644 13         54 $code .= <<"EOM";
645             ${indent} my \$C = \\$varstr;
646             ${indent} if (defined \$\$C) {
647             EOM
648 13 50       34 if ($OPT_IS_OBJECT) {
649 0         0 $code .= <<"EOM";
650             ${indent} my \$C_IS_OBJECT = UNIVERSAL::can(\$\$C, 'can');
651             EOM
652             }
653             }
654              
655 383 50 100     4748 if ( $tname eq T_USE_VARS ) {
    100 100        
    100 100        
    100 100        
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
656 0         0 my $vars = $attr->{NAME};
657 0         0 my @l = grep length, split /\s*,\s*/, $vars;
658 0         0 for my $var (@l) {
659 0 0       0 if ($var =~ tr/a-zA-Z0-9_//c) {
660 0         0 $self->get_parser->_error_wrong_tag_syntax(
661             {
662             fname => $token->get_file,
663             line => $token->get_line,
664             token => "",
665             },
666             $var,
667             'invalid SET_VAR/USE_VARS var name',
668             );
669             }
670             }
671 0         0 push @lexicals, @l;
672             }
673             elsif ( $tname eq T_SET_VAR ) {
674 4         6 my $var = $attr->{NAME};
675 4 100       10 if ($var =~ tr/a-zA-Z0-9_//c) {
676 1         3 $self->get_parser->_error_wrong_tag_syntax(
677             {
678             fname => $token->get_file,
679             line => $token->get_line,
680             token => "",
681             },
682             $var,
683             'invalid SET_VAR/USE_VARS var name',
684             );
685             }
686 3         3 my $value;
687             my $expr;
688 3 50       5 if (exists $attr->{VALUE}) {
    0          
689 3         5 $value = $attr->{VALUE};
690             }
691             elsif (exists $attr->{EXPR}) {
692 0         0 $expr = $attr->{EXPR};
693             }
694             else {
695 0         0 $self->get_parser->_error_wrong_tag_syntax(
696             {
697             fname => $token->get_file,
698             line => $token->get_line,
699             token => "",
700             },
701             $var,
702             'missing VALUE or EXPR',
703             );
704             }
705              
706 3         5 unshift @lexicals, $var;
707 3         11 my $varstr = $class->parse_var($self,
708             %var_args,
709             var => $value,
710             context => $token,
711             compiler => $class,
712             expr => $expr,
713             );
714 3         11 $code .= <<"EOM";
715             ${indent}local \$HTML::Template::Compiled::_lexi_$var = $varstr;
716             EOM
717             }
718             # --------- TMPL_LOOP TMPL_WHILE TMPL_EACH
719             elsif ( ($tname eq T_LOOP || $tname eq T_WHILE || $tname eq T_EACH) ) {
720 52         81 my $var = $attr->{NAME};
721 52   100     168 my $ccontext = $attr->{CONTEXT} || '';
722             my $varstr = $class->parse_var($self,
723             %var_args,
724             var => $var,
725             context => $token,
726             compiler => $class,
727             expr => $attr->{EXPR},
728 52         207 ccontext => $ccontext,
729             );
730 52         95 my $ind = INDENT;
731 52 100       121 if ($self->get_use_query) {
732 13         33 $info_stack->[-1]->{lc $var}->{type} = $tname;
733 13   100     42 $info_stack->[-1]->{lc $var}->{children} ||= {};
734 13         22 push @$info_stack, $info_stack->[-1]->{lc $var}->{children};
735             }
736 52         64 my $lexical = $attr->{ALIAS};
737 52         51 my $insert_break = '';
738 52 100       105 if (defined (my $break = $attr->{BREAK})) {
739 1         2 $break =~ tr/0-9//cd;
740 1 50       3 if ($break) {
741 1         3 $insert_break = qq#local \$__break__ = ! ((\$__ix__+1 ) \% $break);#;
742             }
743             }
744 52         60 push @lexicals, $lexical;
745 52         56 my $sort_keys = '';
746             # SORT=ALPHA or SORT not set => cmp
747             # SORT=NUM => <=>
748             # SORT=0 or anything else => don't sort
749              
750 52         46 my $sort_key_a = '$a';
751 52         47 my $sort_key_b = '$b';
752 52 100       88 if ($attr->{SORTBY}) {
753             my $varstr = $class->parse_var($self,
754             %var_args,
755             var => $attr->{SORTBY},
756 2         5 context => $token,
757             compiler => $class,
758             );
759 2         3 ($sort_key_a, $sort_key_b) = ($varstr, $varstr);
760 2         6 $sort_key_a =~ s/\$\$C/\$hash\{\$a\}/g;
761 2         4 $sort_key_b =~ s/\$\$C/\$hash\{\$b\}/g;
762             }
763              
764 52 100       103 if ($attr->{REVERSE}) {
765 1         2 ($sort_key_b, $sort_key_a) = ($sort_key_a, $sort_key_b);
766             }
767 52         51 my $sort_op = 'cmp';
768 52 100 100     156 if (!defined $attr->{SORT} or uc $attr->{SORT} eq 'ALPHA') {
    50          
769             }
770             elsif (uc $attr->{SORT} eq 'NUM') {
771 2         3 $sort_op = '<=>';
772             }
773 52         103 $sort_keys = "sort \{ $sort_key_a $sort_op $sort_key_b \}";
774              
775 52         41 my $global = '';
776 52 100       116 my $lexi =
777             defined $lexical ? "${indent}local \$HTML::Template::Compiled::_lexi_$lexical = \$\$C;\n" : "";
778 52 100       90 if ($self->get_global_vars) {
779 3         12 my $pop_global = _expr_method(
780             'pushGlobalstack',
781             '$t', '$$C'
782             );
783 3         8 $global = $pop_global->to_string($nlevel).";\n";
784              
785             }
786 52 100       136 if ($tname eq T_WHILE) {
    100          
787 2         5 $code .= "\{" . "\n";
788 2         9 $code .= <<"EOM";
789             $global
790             ${indent}${indent}local \$__ix__ = -1;
791             $insert_break
792             ${indent}${ind}while (my \$next = $varstr) {
793             ${indent}${indent}\$__ix__++;
794             ${indent}${indent}my \$C = \\\$next;
795             $lexi
796             EOM
797 2 50       7 if ($OPT_IS_OBJECT) {
798 0         0 $code .= <<"EOM";
799             ${indent} my \$C_IS_OBJECT = UNIVERSAL::can(\$\$C, 'can');
800             EOM
801             }
802             }
803             elsif ($tname eq T_EACH) {
804             # bug in B::Deparse, so do double ref
805 6         35 $code .= <<"EOM";
806             ${indent}if (my \%hash = eval \{ \%\$\{ \\$varstr \} \} ) \{
807             ${indent}${indent}local \$__ix__ = -1;
808             ${indent}${ind}local (\$__key__,\$__value__);
809             ${indent}${ind}for \$__key__ ($sort_keys keys \%hash) \{
810             ${indent}${ind} local \$__value__ = \$hash\{\$__key__};
811             ${indent}${indent}\$__ix__++;
812             $insert_break
813             EOM
814             }
815             else {
816              
817 44         49 my $join_code = '';
818 44 100       87 if (defined (my $join = $attr->{JOIN})) {
819 2         8 my $dump = HTML::Template::Compiled->dump_var($join, 'join');
820 2         103 $dump =~ s{\$join *= *}{};
821 2         5 $dump =~ s{;$}{};
822 2         7 $join_code = <<"EOM";
823             \{
824             unless (\$__ix__ == \$[) \{
825             $output $dump;
826             \}
827             \}
828             EOM
829            
830             }
831             # bug in B::Deparse, so do double ref
832 44         222 $code .= <<"EOM";
833             ${indent}if (my \@array = eval { \@\$\{ \\$varstr \} } )\{
834             ${indent}${ind}local \$__size__ = \$#array;
835             $global
836              
837             ${indent}${ind}
838             ${indent}${ind}for \$__ix__ (\$[..\$__size__ + \$[) \{
839             ${indent}${ind}${ind}my \$C = \\ (\$array[\$__ix__]);
840             $insert_break
841             $lexi
842             $join_code
843             EOM
844 44 50       127 if ($OPT_IS_OBJECT) {
845 0         0 $code .= <<"EOM";
846             ${indent} my \$C_IS_OBJECT = UNIVERSAL::can(\$\$C, 'can');
847             EOM
848             }
849             }
850             }
851              
852             # --------- TMPL_ELSE
853             elsif ($tname eq T_ELSE) {
854 5         8 my $exp = "\} else \{";
855 5         11 $code .= $exp;
856             }
857              
858             # --------- TMPL_IF TMPL_UNLESS TMPL_ELSIF TMPL_IF_DEFINED
859             elsif ($tname eq T_IF) {
860 19         90 my $expr = $class->_compile_OPEN_IF($self, {
861             %var_args,
862             context => $token,
863             },);
864 19         66 $code .= $expr;
865             }
866             elsif ($tname eq T_IF_DEFINED) {
867 4         15 my $expr = $class->_compile_OPEN_IF_DEFINED($self, {
868             %var_args,
869             context => $token,
870             },);
871 4         13 $code .= $expr;
872             }
873             elsif ($tname eq T_UNLESS) {
874 2         13 my $expr = $class->_compile_OPEN_UNLESS($self, {
875             %var_args,
876             context => $token,
877             },);
878 2         8 $code .= $expr;
879             }
880              
881             # --------- TMPL_ELSIF
882             elsif ($tname eq T_ELSIF) {
883 7         15 my $var = $attr->{NAME};
884             my $varstr = $class->parse_var($self,
885             %var_args,
886             var => $var,
887             context => $token,
888             compiler => $class,
889             expr => $attr->{EXPR},
890 7         54 );
891 7         37 my $operand = _expr_literal($varstr);
892 7         22 my $exp = _expr_elsif($operand);
893 7         19 my $str = $exp->to_string($nlevel);
894 7         64 $code .= $str . $/;
895             }
896              
897             # --------- TMPL_SWITCH
898             elsif ($tname eq T_SWITCH) {
899 3         4 my $var = $attr->{NAME};
900 3         4 push @switches, 0;
901             my $varstr = $class->parse_var($self,
902             %var_args,
903             var => $var,
904             context => $token,
905             compiler => $class,
906             expr => $attr->{EXPR},
907 3         13 );
908 3         11 $code .= <<"EOM";
909             ${indent}SWITCH: for my \$_switch ($varstr) \{
910             EOM
911             }
912            
913             # --------- TMPL_CASE
914             elsif ($tname eq T_CASE) {
915 5         6 my $val = $attr->{NAME};
916             #$val =~ s/^\s+//;
917 5 100       11 if ( $switches[$#switches] ) {
918              
919             # we aren't the first case
920 2         4 $code .= qq#${indent}last SWITCH;\n${indent}\}\n#;
921             }
922             else {
923 3         5 $switches[$#switches] = 1;
924             }
925 5 100 66     17 if ( !length $val or uc $val eq 'DEFAULT' ) {
926 1         3 $code .= qq#${indent}if (1) \{\n#;
927             }
928             else {
929 4         6 $val =~ tr/'//d;
930 4         6 my @splitted = split /,/, $val;
931 4         5 my $is_default = '';
932             @splitted = grep {
933 4         5 uc $_ eq 'DEFAULT'
934 6 100       13 ? do {
935 1         1 $is_default = ' or 1 ';
936 1         3 0;
937             }
938             : 1
939             } @splitted;
940 4         4 my $values = join ",", map { qq#'$_'# } @splitted;
  5         10  
941 4 100 100     13 if ($is_default or @splitted > 1) {
942 2         8 $code .=
943             qq#${indent}if (grep \{ \$_switch eq \$_ \} $values $is_default) \{\n#;
944             }
945             else {
946 2         5 $code .=
947             qq#${indent}if ( \$_switch eq $values) \{\n#;
948             }
949             }
950             }
951              
952             # --------- TMPL_INCLUDE_STRING
953             elsif ($tname eq T_INCLUDE_STRING) {
954 1         3 my $var = $attr->{NAME};
955             my $varstr = $class->parse_var($self,
956             %var_args,
957             var => $var,
958             context => $token,
959             compiler => $class,
960             expr => $attr->{EXPR},
961 1         5 );
962 1         3 my $ref = ref $self;
963 1         5 $code .= <<"EOM";
964             \{
965             my \$scalar = $varstr;
966             my \$new = \$t->new_scalar_from_object(\$scalar);
967             $globalstack
968 1 50       5 $output \$new->get_code()->(\$new,\$P,\$C@{[$out_fh ? ",\$OFH" : '']});
969             \}
970             EOM
971              
972             }
973              
974             # --------- TMPL_INCLUDE_VAR
975             elsif ($tname eq T_INCLUDE_VAR or $tname eq T_INCLUDE or $tname eq T_WRAPPER) {
976 26         33 my $filename;
977             my $varstr;
978 26         70 my $path = $self->get_path();
979 26         27 my $dir;
980 26 100       59 my $dynamic = $tname eq T_INCLUDE_VAR ? 1 : 0;
981 26         30 my $fullpath = "''";
982              
983 26         28 my $cwd;
984 26 100       57 unless ($self->get_scalar) {
985 22         754 $dir = dirname($fname);
986 22 100       64 if ($self->get_search_path == 1) {
    100          
987             }
988             elsif ($self->get_search_path == 2) {
989 2         2 $cwd = $dir;
990             }
991             else {
992 16         31 $path = [ $dir ] ;
993             }
994             }
995 26 100       52 if ($dynamic) {
996             # dynamic filename
997 1         1 my $dfilename = $attr->{NAME};
998 1 50       3 if ($self->get_use_query) {
999 0         0 $info_stack->[-1]->{lc $dfilename}->{type} = $tname;
1000             }
1001             $varstr = $class->parse_var($self,
1002             %var_args,
1003             var => $dfilename,
1004             context => $token,
1005             compiler => $class,
1006             expr => $attr->{EXPR},
1007 1         6 );
1008             }
1009             else {
1010             # static filename
1011 25         43 $filename = $attr->{NAME};
1012 25         101 $fullpath = $self->createFilename( [@$path], \$filename, $cwd );
1013 24 100       69 if ($self->get_use_query) {
1014 3         9 $info_stack->[-1]->{lc $filename}->{type} = $tname;
1015             }
1016 24         82 $varstr = $self->quote_file($filename);
1017             # generate included template
1018             {
1019 24         28 D && $self->log("compile include $filename!!");
  24         24  
1020 24         46 my $recursed = ++$HTML::Template::Compiled::COMPILE_STACK{$fullpath};
1021 24 100       70 if ($recursed <= 1) {
1022 23         17 my $cached_or_new;
1023 23 50       71 $self->compile_early() and $cached_or_new
1024             = $self->new_from_object(
1025             #[@$path, \$self->get_file], $filename, '', $self->get_cache_dir
1026             $path, $filename, '', $self->get_cache_dir
1027             );
1028 23         83 $self->get_includes()->{$fullpath}
1029             = [$path, $filename, $cached_or_new];
1030             }
1031 24         51 --$HTML::Template::Compiled::COMPILE_STACK{$fullpath};
1032 24         63 $fullpath = $self->quote_file($fullpath);
1033             }
1034             }
1035             #print STDERR "include $varstr\n";
1036 25         63 my $cache = $self->get_cache_dir;
1037             $path = defined $path
1038             ? '['
1039 25 50       87 . join( ',', map { $self->quote_file($_) } @$path ) . ']'
  27         62  
1040             : 'undef';
1041 25 100       69 $cwd = defined $cwd ? $self->quote_file($cwd) : 'undef';
1042 25 100       58 $cache = defined $cache ? $self->quote_file($cache) : 'undef';
1043 25 100       78 if ($dynamic) {
    100          
1044 1         5 $code .= <<"EOM";
1045             # ---------- INCLUDE_VAR
1046             \{
1047             if (defined (my \$file = $varstr)) \{
1048             my \$fullpath = \$t->createFilename( $path, \\\$file, $cwd );
1049             my \$recursed = ++\$HTML::Template::Compiled::FILESTACK{\$fullpath};
1050             \$HTML::Template::Compiled::FILESTACK{\$fullpath} = 0, die "HTML::Template: recursive include of " . \$fullpath . " \$recursed times (max \$HTML::Template::Compiled::MAX_RECURSE)"
1051             if \$recursed > \$HTML::Template::Compiled::MAX_RECURSE;
1052             my \$include = \$t->get_includes()->{\$fullpath};
1053             my \$new = \$include ? \$include->[2] : undef;
1054             if (!\$new || HTML::Template::Compiled::needs_new_check($cache||'',\$file,\$t->get_expire_time)) \{
1055             \$new = \$t->new_from_object($path,\$file,\$fullpath,$cache);
1056             \}
1057             $globalstack
1058 1 50       9 $output \$new->get_code()->(\$new,\$P,\$C@{[$out_fh ? ",\$OFH" : '']});
1059             --\$HTML::Template::Compiled::FILESTACK{\$fullpath} or delete \$HTML::Template::Compiled::FILESTACK{\$fullpath};
1060             \}
1061             \}
1062             EOM
1063             }
1064             elsif ($tname eq T_WRAPPER) {
1065 6         16 push @outputs, '$OUT' . (1 + scalar @outputs) . ' .= ';
1066 6         6 $output = $outputs[-1];
1067 6         6 my $wrapped = '';
1068 6         6 $code .= <<"EOM";
1069             # ---------- WRAPPER
1070             \{
1071 6         16 my \$OUT@{[ scalar @outputs ]};
1072             EOM
1073 6         6 my $argument_fh = 'undef';
1074 6 100       13 if ($out_fh) {
1075 3         4 $wrapped .= <<"EOM";
1076             my \$tmp_var = '';
1077             open my \$tmp_fh, '>', \\\$tmp_var;
1078             EOM
1079 3         4 $argument_fh = "\$tmp_fh";
1080             }
1081 6         6 $wrapped .= <<"EOM";
1082 6         30 my \$_WRAPPED = \$OUT@{[ scalar @outputs ]};
1083             my \$recursed = ++\$HTML::Template::Compiled::FILESTACK{$fullpath};
1084             \$HTML::Template::Compiled::FILESTACK{$fullpath} = 0, die "HTML::Template: recursive include of " . $fullpath . " \$recursed times (max \$HTML::Template::Compiled::MAX_RECURSE)"
1085             if \$recursed > \$HTML::Template::Compiled::MAX_RECURSE;
1086             my \$include = \$t->get_includes()->{$fullpath};
1087             my \$new = \$include ? \$include->[2] : undef;
1088             if (!\$new) {
1089             \$new = \$t->new_from_object($path,$varstr,$fullpath,$cache);
1090             }
1091             $globalstack
1092             $outputs[-2] \$new->get_code()->(\$new,\$P,\$C, $argument_fh, { wrapped => \$_WRAPPED });
1093             --\$HTML::Template::Compiled::FILESTACK{$fullpath} or delete \$HTML::Template::Compiled::FILESTACK{$fullpath};
1094 6         13 \$OUT@{[ scalar @outputs ]} = '';
1095             EOM
1096 6 100       11 if ($out_fh) {
1097 3         7 $wrapped .= <<"EOM";
1098             $outputs[-2] \$tmp_var;
1099             EOM
1100             }
1101 6         6 $wrapped .= <<"EOM";
1102             \}
1103             EOM
1104 6         15 push @wrapped, $wrapped;
1105             }
1106             else {
1107 18         94 $code .= <<"EOM";
1108             # ---------- INCLUDE
1109             \{
1110             my \$recursed = ++\$HTML::Template::Compiled::FILESTACK{$fullpath};
1111             \$HTML::Template::Compiled::FILESTACK{$fullpath} = 0, die "HTML::Template: recursive include of " . $fullpath . " \$recursed times (max \$HTML::Template::Compiled::MAX_RECURSE)"
1112             if \$recursed > \$HTML::Template::Compiled::MAX_RECURSE;
1113             my \$include = \$t->get_includes()->{$fullpath};
1114             my \$new = \$include ? \$include->[2] : undef;
1115             if (!\$new) {
1116             \$new = \$t->new_from_object($path,$varstr,$fullpath,$cache);
1117             }
1118             $globalstack
1119 18 50       143 $output \$new->get_code()->(\$new,\$P,\$C@{[$out_fh ? ",\$OFH" : '']});
1120             --\$HTML::Template::Compiled::FILESTACK{$fullpath} or delete \$HTML::Template::Compiled::FILESTACK{$fullpath};
1121             \}
1122             EOM
1123             }
1124             }
1125             else {
1126             # user defined
1127             #warn Data::Dumper->Dump([\$token], ['token']);
1128             #warn Data::Dumper->Dump([\$tags], ['tags']);
1129 255         303 my $subs = $tags->{$tname};
1130 255 50 66     658 if ($subs && $subs->{open}) {
1131 3         10 $code .= $subs->{open}->($self, $token, {
1132             out => $output,
1133             });
1134             }
1135             }
1136             }
1137             elsif ($token->is_close) {
1138             # --------- / TMPL_IF TMPL UNLESS TMPL_WITH
1139 99 100 100     506 if ($tname =~ m/^(?:IF|UNLESS|WITH|IF_DEFINED)$/) {
    100 100        
    100          
    50          
1140 38         53 my $var = $attr->{NAME};
1141 38 100       90 $var = '' unless defined $var;
1142             #print STDERR "============ IF ($text)\n";
1143 38         40 $code .= "\}" ;
1144 38 100 100     94 if ($self->get_global_vars && $tname eq 'WITH') {
1145 5         9 $code .= qq{\n} . $indent . qq#\$t->popGlobalstack;\n#;
1146             }
1147 38 100       120 $code .= ($tname eq 'WITH' ? "\}" : '') . qq{\n};
1148             }
1149              
1150             # --------- / TMPL_SWITCH
1151             elsif ($tname eq T_SWITCH) {
1152 3 50       5 if ( $switches[$#switches] ) {
1153              
1154             # we had at least one CASE, so we close the last if
1155 3         5 $code .= "\} # last case\n";
1156             }
1157 3         3 $code .= "\}\n";
1158 3         4 pop @switches;
1159             }
1160            
1161             # --------- / TMPL_LOOP TMPL_WHILE
1162             elsif ($tname eq T_LOOP || $tname eq T_WHILE || $tname eq T_EACH) {
1163 52         57 pop @lexicals;
1164 52 100       120 if ($self->get_use_query) {
1165 13         14 pop @$info_stack;
1166             }
1167 52         64 $code .= "\}";
1168 52 100       108 if ($self->get_global_vars) {
1169 3         10 $code .= qq{\n} . $indent . qq#\$t->popGlobalstack;\n#;
1170             }
1171 52         94 $code .= "\} # end loop\n";
1172             }
1173             elsif ($tname eq T_WRAPPER) {
1174 6         15 $code .= $wrapped[-1];
1175 6         4 pop @wrapped;
1176 6         6 pop @outputs;
1177 6         8 $output = $outputs[-1];
1178 6         8 $code .= <<"EOM";
1179             EOM
1180             }
1181             else {
1182             # user defined
1183             #warn Data::Dumper->Dump([\$token], ['token']);
1184             #warn Data::Dumper->Dump([\$tags], ['tags']);
1185 0         0 my $subs = $tags->{$tname};
1186 0 0 0     0 if ($subs && $subs->{close}) {
1187 0         0 $code .= $subs->{close}->($self, $token, {
1188             out => $output,
1189             });
1190             }
1191             }
1192             }
1193              
1194             }
1195 149 100       370 if ($self->get_use_query) {
1196 10         28 $self->set_parse_tree($info);
1197             }
1198 149         357 my @use_vars = grep length, keys %use_vars;
1199 149 100       279 if (@use_vars) {
1200             # $header .= qq#use vars qw/ @{[ map { '$_lexi_'.$_ } @use_vars ]} /;\n#;
1201             }
1202             #warn Data::Dumper->Dump([\$info], ['info']);
1203 149         194 $code .= qq#return \$OUT;\n#;
1204 149         396 $code = $header . $code . "\n} # end of sub\n";
1205              
1206             #$code .= "\n} # end of sub\n";
1207 149 50       343 print STDERR "# ----- code \n$code\n# end code\n" if $self->get_debug->{options} & HTML::Template::Compiled::DEBUG_COMPILED();
1208              
1209             # untaint code
1210 149 50       534 if ( $code =~ m/(\A.*\z)/ms ) {
1211             # we trust our template
1212 149         400 $code = $1;
1213             }
1214             else {
1215 0         0 $code = "";
1216             }
1217 149         180 my $l = length $code;
1218             #print STDERR "length $fname: $l\n";
1219 36     36   200 my $sub = eval $code;
  36     36   44  
  36     36   2361  
  36     25   146  
  36     24   42  
  36     24   819  
  36     20   116  
  36     19   41  
  36     19   5711  
  25     15   1151  
  25     14   623  
  25     14   1584  
  24     12   96  
  24         23  
  24         488  
  24         67  
  24         21  
  24         3378  
  20         2640  
  20         1439  
  20         2630  
  19         77  
  19         46  
  19         575  
  19         61  
  19         22  
  19         1686  
  15         975  
  15         642  
  15         1620  
  14         64  
  14         21  
  14         496  
  14         51  
  14         18  
  14         1122  
  12         52  
  12         16  
  12         1425  
  149         12469  
1220             #die "code: $@ ($code)" if $@;
1221 149 50       440 die "code: $@" if $@;
1222 149         2265 return $code, $sub;
1223             }
1224             sub _compile_OPEN_VAR {
1225 235     235   449 my ($self, $htc, $args) = @_;
1226             #print STDERR "===== VAR ($text)\n";
1227 235         251 my $token = $args->{context};
1228 235         630 my $attr = $token->get_attributes;
1229 235         261 my $var = $attr->{NAME};
1230             #my $expr = $attr->{EXPR};
1231 235         203 my $expr;
1232              
1233             my $varstr = $self->parse_var($htc,
1234             %$args,
1235             var => $var,
1236             context => $token,
1237             compiler => $self,
1238             expr => $attr->{EXPR},
1239 235         864 );
1240              
1241             #print "line: $text var: $var ($varstr)\n";
1242 235         440 my $exp = $varstr;
1243             # ---- default
1244 235         179 my $default;
1245 235 100       453 if (defined $attr->{DEFAULT}) {
1246 4         13 $default = $self->dump_string($attr->{DEFAULT});
1247 4         18 $exp = _expr_ternary(
1248             _expr_defined($exp),
1249             $exp,
1250             $default,
1251             )->to_string;
1252             }
1253             # ---- escapes
1254 235         542 my $escape = $htc->get_default_escape;
1255 235 100       438 if (exists $attr->{ESCAPE}) {
1256 14         22 $escape = $attr->{ESCAPE};
1257             }
1258 235 100       370 $exp = $self->_escape_expression($exp, $escape) if $escape;
1259 235         431 return $exp;
1260             }
1261              
1262             sub _compile_OPEN_IF {
1263 19     19   27 my ($self, $htc, $args) = @_;
1264             #print STDERR "============ IF ($text)\n";
1265 19         56 my $var = $args->{context}->get_attributes->{NAME};
1266 19         24 my $token = $args->{context};
1267 19         36 my $attr = $token->get_attributes;
1268             my $varstr = $self->parse_var($htc,
1269             %$args,
1270             var => $var,
1271             compiler => $self,
1272             expr => $attr->{EXPR},
1273 19         75 );
1274 19         68 return "if ($varstr) \{";
1275             }
1276             sub _compile_OPEN_UNLESS {
1277 2     2   4 my ($self, $htc, $args) = @_;
1278             #print STDERR "============ IF ($text)\n";
1279 2         7 my $var = $args->{context}->get_attributes->{NAME};
1280 2         4 my $token = $args->{context};
1281 2         5 my $attr = $token->get_attributes;
1282             my $varstr = $self->parse_var($htc,
1283             %$args,
1284             var => $var,
1285             compiler => $self,
1286             expr => $attr->{EXPR},
1287 2         11 );
1288 2         9 return "unless ($varstr) \{";
1289             }
1290             sub _compile_OPEN_IF_DEFINED {
1291 4     4   4 my ($self, $htc, $args) = @_;
1292             #print STDERR "============ IF ($text)\n";
1293 4         12 my $var = $args->{context}->get_attributes->{NAME};
1294 4         3 my $token = $args->{context};
1295 4         7 my $attr = $token->get_attributes;
1296             my $varstr = $self->parse_var($htc,
1297             %$args,
1298             var => $var,
1299             compiler => $self,
1300             expr => $attr->{EXPR},
1301 4         15 );
1302 4         10 return "if (defined ($varstr)) \{";
1303             }
1304              
1305             1;
1306              
1307             __END__