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   179 use strict;
  50         59  
  50         1252  
3 50     50   153 use warnings;
  50         53  
  50         1583  
4 48     48   701 use Data::Dumper;
  48         334  
  48         3079  
5 48     48   192 use Carp qw(croak carp);
  48         52  
  48         1904  
6 48     48   169 use HTML::Template::Compiled::Expression qw(:expressions);
  48         51  
  48         4893  
7 47     47   195 use HTML::Template::Compiled::Utils qw(:walkpath);
  47         51  
  47         4658  
8 46     46   192 use File::Basename qw(dirname);
  46         50  
  46         2429  
9              
10             our $VERSION = '1.002_001'; # TRIAL VERSION
11              
12             our $DISABLE_NEW_ALIAS = 0;
13              
14 46     46   162 use Carp qw(croak carp);
  46         57  
  46         2024  
15 45     45   154 use constant D => 0;
  45         53  
  45         2749  
16              
17 39     39   136 use constant T_VAR => 'VAR';
  39         45  
  39         1574  
18 39     39   140 use constant T_IF => 'IF';
  39         49  
  39         1617  
19 39     39   141 use constant T_UNLESS => 'UNLESS';
  39         49  
  39         1534  
20 39     39   124 use constant T_ELSIF => 'ELSIF';
  39         45  
  39         1371  
21 39     39   132 use constant T_ELSE => 'ELSE';
  39         44  
  39         1379  
22 39     39   130 use constant T_IF_DEFINED => 'IF_DEFINED';
  39         41  
  39         1587  
23 39     39   129 use constant T_END => '__EOT__';
  39         54  
  39         1360  
24 39     39   125 use constant T_WITH => 'WITH';
  39         43  
  39         1297  
25 39     39   123 use constant T_SWITCH => 'SWITCH';
  39         42  
  39         1570  
26 39     39   133 use constant T_CASE => 'CASE';
  39         45  
  39         1408  
27 39     39   133 use constant T_INCLUDE => 'INCLUDE';
  39         50  
  39         1391  
28 39     39   127 use constant T_LOOP => 'LOOP';
  39         265  
  39         1660  
29 39     39   141 use constant T_WHILE => 'WHILE';
  39         35  
  39         1279  
30 39     39   116 use constant T_EACH => 'EACH';
  39         77  
  39         1774  
31 39     39   120 use constant T_INCLUDE_VAR => 'INCLUDE_VAR';
  39         38  
  39         1553  
32 39     39   127 use constant T_INCLUDE_STRING => 'INCLUDE_STRING';
  39         38  
  39         1393  
33 39     39   118 use constant T_USE_VARS => 'USE_VARS';
  39         37  
  39         1264  
34 39     39   120 use constant T_SET_VAR => 'SET_VAR';
  39         43  
  39         1653  
35 38     38   119 use constant T_WRAPPER => 'WRAPPER';
  38         40  
  38         1269  
36              
37 38     38   120 use constant INDENT => ' ';
  38         59  
  38         1282  
38              
39 38     38   118 use constant NO_TAG => 0;
  38         46  
  38         1301  
40 36     36   118 use constant OPENING_TAG => 1;
  36         32  
  36         1184  
41 36     36   111 use constant CLOSING_TAG => 2;
  36         501  
  36         1223  
42              
43 36     36   120 use constant ATTR_ESCAPES => 0;
  36         39  
  36         1161  
44 36     36   108 use constant ATTR_TAGS => 1;
  36         33  
  36         1150  
45 36     36   103 use constant ATTR_NAME_RE => 2;
  36         39  
  36         78016  
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         6  
52 3         12 $_[0]->[ATTR_TAGS]->{$key} = $_[1]->{$key};
53             }
54             }
55 151     151 0 203 sub get_tags { $_[0]->[ATTR_TAGS] }
56 151     151 0 511 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         22 for my $key (keys %$escapes) {
69 4         5 my $def = $escapes->{$key};
70 4         5 my $sub;
71 4 50       11 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       9 if (ref $sub eq 'CODE') {
81 3         17 $ESCAPES{ $plug_class }->{ $key }->{code} = $sub;
82             }
83             else {
84 1         2 $ESCAPES{ $plug_class }->{ $key }->{code} = \&{ $sub };
  1         4  
85             }
86             }
87             }
88              
89             sub add_escapes {
90 3     3 0 6 my ($self, $plug_class, $new_escapes) = @_;
91 3         8 my $escapes = $self->get_escapes;
92 3         20 for my $key (keys %$new_escapes) {
93 4         13 $escapes->{ $key } = $plug_class;
94             }
95             }
96              
97             sub new {
98 131     131 0 177 my $class = shift;
99 131         183 my $self = [];
100 131         182 bless $self, $class;
101 131         298 $self->set_escapes({});
102 131         257 return $self;
103             }
104              
105             sub _escape_expression {
106 14     14   18 my ( $self, $exp, $escape ) = @_;
107 14 50       23 return $exp unless $escape;
108 14         43 my @escapes = split m/\|/, uc $escape;
109 14         25 my $escapes = $self->get_escapes();
110 14         26 for (@escapes) {
111 15 100       85 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         11 $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         3 $exp =
133             _expr_function( 'HTML::Template::Compiled::Utils::escape_ijson',
134             $exp, );
135             }
136             elsif ( $_ eq 'DUMP' ) {
137 1         3 $exp = _expr_method( 'dump', _expr_literal('$t'), $exp, );
138             }
139             elsif (my $plug_class = $escapes->{$_}) {
140 4         10 my $subref = "\$HTML::Template::Compiled::Compiler::ESCAPES\{'$plug_class'\}->\{'$_'\}->\{code\}";
141 4         5 my @args = $exp;
142 4 50       13 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         29 $exp = HTML::Template::Compiled::Expression::SubrefCall->new( $subref, @args );
155             }
156             }
157 14 50       55 return ref $exp ? $exp->to_string : $exp;
158             }
159              
160             sub init_name_re {
161 151     151 0 357 my ($self, %args) = @_;
162 151         1449 my $re = qr#
163             \Q$args{deref}\E |
164             \Q$args{method_call}\E |
165             \Q$args{formatter_path}\E
166             #x;
167 151         628 $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 1492 my ( $self, $t, %args ) = @_;
189 368         379 my $lexicals = $args{lexicals};
190 368         299 my $context = $args{context};
191             # calling context. 'list' or empty (which means scalar)
192 368   100     1062 my $ccontext = $args{ccontext} || '';
193              
194              
195 368 100 66     798 if (!defined $args{var} and defined $args{expr}) {
196 27         20 my $compiler = $args{compiler};
197             return HTML::Template::Compiled::Expr->parse_expr(
198             $compiler,
199             $t,
200             %args,
201             expr => $args{expr},
202 27         107 context => $context,
203             );
204             }
205              
206              
207 341 50       1146 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       704 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         631 my $lexi = join '|', grep defined, @$lexicals;
223 336         384 my $varname = '$var';
224 336         605 my $re = $self->get_name_re;
225             # warn __PACKAGE__.':'.__LINE__.": re: $re\n";
226             #warn __PACKAGE__.':'.__LINE__.": ========== ($args{var})\n";
227 336         288 my $root = 0;
228 336         246 my $up_stack = 0;
229 336         263 my $initial_var = '$$C';
230 336         246 my $is_object_var = '$C_IS_OBJECT';
231 336         226 my $root_hash = 0;
232 336         890 my $OPT_INITIAL_VAR = $t->get_optimize->{initial_var};
233 336         695 my $OPT_IS_OBJECT = $t->get_optimize->{object_check};
234 336         653 my $OPT_ROOT_HASH = $t->get_optimize->{root_hash};
235 336 50       503 my $use_initial_var = $OPT_INITIAL_VAR ? 1 : 0;
236 336 100 100     637 if ( $t->get_loop_context && $args{var} =~ m/^__(\w+)__$/ ) {
237 54 50       126 if (exists $loop_context{ lc $args{var} }) {
238 54         69 my $lc = $loop_context{ lc $args{var} };
239 54         151 return $lc;
240             }
241             }
242             # explicitly use aliases with '$' at the beginning
243 282 100 100     3845 if (not $DISABLE_NEW_ALIAS and $args{var} =~ s/^\$(\w+)//) {
    100 100        
    100 100        
    100          
244 9         21 $initial_var = "\$HTML::Template::Compiled::_lexi_$1";
245 9         13 $is_object_var = '';
246             }
247             elsif ($lexi and $args{var} =~ s/^($lexi)($re)/$2/) {
248 2         3 $initial_var = "\$HTML::Template::Compiled::_lexi_$1";
249 2         2 $is_object_var = '';
250             }
251             elsif ( $args{var} =~ m/^_/ && $args{var} !~ m/^__(\w+)__$/ ) {
252 16         57 $args{var} =~ s/^_//;
253 16         20 $root = 0;
254 16         20 $is_object_var = '';
255             }
256             elsif ( my @roots = $args{var} =~ m/\G($re)/gc) {
257             #print STDERR "ROOTS: (@roots)\n";
258 35 100       85 $root = 1 if @roots == 1;
259 35         318 $args{var} =~ s/^($re)+//;
260 35 100       114 if (@roots > 1) {
    50          
261 1 50       5 croak "Cannot navigate up the stack" if !$t->get_global_vars & 2;
262 1         3 $up_stack = $#roots;
263 1         3 $initial_var = "\$t->get_globalstack->[-$up_stack]";
264 1         3 $use_initial_var = 0;
265 1         2 $is_object_var = '';
266             }
267             elsif (@roots == 1) {
268 34         36 $initial_var = '$P';
269 34         30 $is_object_var = '$P_IS_OBJECT';
270 34 50       70 $root_hash = 1 if $OPT_ROOT_HASH;
271             }
272             }
273 282         1606 my @split = split m/(?=$re)/, $args{var};
274             @split = map {
275 282         393 my @ret;
  306         233  
276 306         240 my $count = 0;
277 306 100       549 if (s/#\z//) {
278 4         5 $count = 1;
279             }
280 306 100       513 if ( m/(.*)\[(-?\d+)\]/ ) {
281 15         40 my @slice = "[$2]";
282 15         22 my $var = "$1";
283 15         39 while ($var =~ s/\[(-?\d+)\]\z//) {
284 1         4 unshift @slice, "[$1]";
285             }
286 15         29 @ret = ($var, @slice)
287             }
288             else {
289 291         449 @ret = $_
290             }
291 306 100       523 push @ret, '#' if $count;
292 306         961 @ret;
293             } @split;
294 282         251 my @paths;
295             #print STDERR "paths: (@split)\n";
296 282         236 my $count = 0;
297 282         614 my $use_objects = $t->get_objects;
298 282 100       442 my $strict = $use_objects eq 'strict' ? 1 : 0;
299 282         337 my $method_args = '';
300 282         205 my $varstr = '';
301             @split = map {
302 282         281 s#\\#\\\\#g;
  326         325  
303 326         267 s#'#\\'#g;
304 326 100       711 length $_ ? $_ : ()
305             } @split;
306 282 100       528 if (@split == 1) {
307 223         217 $varname = $initial_var;
308             }
309 282         311 my $used_initial_var = 0;
310 282         643 for my $i (0 .. $#split) {
311 322 100 100     1152 if ($i == $#split and defined $args{method_args}) {
312 1         2 $method_args = $args{method_args};
313             }
314 322         467 my $around = ['', ''];
315 322 100 100     934 if ($i == $#split and $ccontext eq 'list') {
316 2 100       12 if ($context->get_name eq 'EACH') {
    50          
317 1         3 $around = ['+{', '}'];
318             }
319             elsif ($context->get_name eq 'LOOP') {
320 1         2 $around = ['[', ']'];
321             }
322             }
323 322         342 my $p = $split[$i];
324             #warn __PACKAGE__.':'.__LINE__.": path: $p\n";
325 322         270 my $copy = $p;
326 322         258 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     2929 if ( $p =~ s/^\[(-?\d+)\]$/$1/ ) {
    100          
    100          
    100          
    100          
334             # array index
335 16         23 $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         9 $deref = 1;
348             }
349             elsif ( $p =~ s/^\Q$args{formatter_path}// ) {
350 3         3 $formatter_call = 1;
351             }
352             else {
353             # guess
354 254         258 $guess = 1;
355             }
356 322 100 100     996 if ($method_call || $guess) {
357 289 100       1008 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     1081 if ($method_call || $guess || $deref) {
      100        
364 299 100 100     855 if ($count == 0 && $t->get_global_vars & 1) {
365 23         19 $try_global = 1;
366 23         21 $method_call = $guess = $deref = 0;
367             }
368             }
369              
370 322 100       616 my $path = $t->get_case_sensitive ? $p : lc $p;
371 322         281 my $code;
372 322 100 100     1295 if ( defined $array_index ) {
    100          
    100          
    100          
    100          
    50          
373             # array index
374 16         24 $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         39 $code = "\$t->try_global($varname, '$path')";
384             }
385              
386             elsif ( $method_call || $guess) {
387             # maybe method call
388 264         426 my $check_object = "UNIVERSAL::can($varname,'can')";
389 264         237 my $local_varname = $varname;
390 264 100       419 if ($i == 0) {
391 236 100       330 if ($use_initial_var) {
392 235         187 $local_varname = $initial_var;
393 235         186 $used_initial_var = 1;
394 235         300 $check_object = "UNIVERSAL::can($local_varname,'can')";
395             }
396 236 50 33     433 if ($OPT_IS_OBJECT and $is_object_var) {
397 0         0 $check_object = $is_object_var;
398             }
399              
400             }
401 264 50 66     874 if ($i == 0 and $root_hash) {
    100          
402 0         0 $code = "$local_varname\->\{'$path'\}";
403             }
404             elsif ($strict) {
405 261         669 $code = "($check_object ? $local_varname->$p($method_args) : $local_varname\->\{'$path'\})";
406             }
407             else {
408 3         10 $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         16 $code = "$varname\->\{'$path'\}";
414             }
415              
416             elsif ( $formatter_call ) {
417 3         5 $code = "\$t->_walk_formatter($varname, '$p', @{[$t->get_global_vars]})";
  3         7  
418             }
419 322         444 $code = $around->[0] . $code . $around->[1];
420 322 100       477 if (0 or @split > 1) {
421 99 100 100     255 if ($used_initial_var and $i==0) {
422 31         73 $varstr .= "my $varname = $code;";
423             }
424             else {
425 68         127 $varstr .= "$varname = $code;";
426             }
427             }
428             else {
429 223         218 $varstr = $code;
430             }
431              
432 322         674 $count++;
433             }
434             #my $final = $context->get_name eq 'VAR' ? 1 : 0;
435 282 100       417 if (0 or @split > 1) {
436 42 100       52 if ($used_initial_var) {
437 31         67 $varstr = "do { $varstr $varname }";
438             }
439             else {
440 11         28 $varstr = "do { my $varname = $initial_var; $varstr $varname }";
441             }
442             }
443             else {
444 240 100       415 $varstr = $initial_var unless length $varstr;
445 240         234 $varstr = "$varstr";
446             }
447 282         1019 return $varstr;
448             }
449              
450             sub dump_string {
451 322     322 0 355 my ($self, $string) = @_;
452 322         894 my $dump = HTML::Template::Compiled->dump_var($string, 'string');
453 322 50       29120 $dump =~ s#^\$string *= *## or die "dump_string() failed";
454 322         756 $dump =~ s/;$//;
455 322         1249 return $dump;
456             }
457              
458             sub compile {
459 161     161 0 238 my ( $class, $self, $text, $fname ) = @_;
460 161         134 D && $self->log("compile($fname)");
461 161 100       374 if ( my $filter = $self->get_filter ) {
462 7         150 require HTML::Template::Compiled::Filter;
463 7         22 $filter->filter($text);
464             }
465 161         345 my $parser = $self->get_parser;
466 161         486 my @p = $parser->parse($fname, $text);
467 151 100       609 if (my $df = $self->get_debug->{file}) {
468 6 100       25 my $debugfile = $df =~ m/short/ ? $self->get_filename : $self->get_file;
469 6 100       16 if ($df =~ m/start/) {
470 4         14 unshift @p,
471             HTML::Template::Compiled::Token::Text->new([
472             '', 0,
473             undef, undef, undef, $self->get_file, 0
474             ]);
475             }
476 6 100       16 if ($df =~ m/end/) {
477 4         14 push @p,
478             HTML::Template::Compiled::Token::Text->new([
479             '', 0,
480             undef, undef, undef, $self->get_file, 0
481             ]);
482             }
483             }
484 151         204 my $code = '';
485 151         259 my $info = {}; # for query()
486 151         207 my $info_stack = [$info];
487              
488 151         298 my $test = $self->get_debug->{options};
489             # got this trick from perlmonks.org
490             my $anon = D
491 151 50       330 || ($self->get_debug->{options} & HTML::Template::Compiled::DEBUG_COMPILED()) ? qq{local *__ANON__ = "htc_$fname";\n} : '';
492              
493 36     36   241 no warnings 'uninitialized';
  36         65  
  36         122835  
494 151         161 my $string_output = '$OUT .= ';
495 151         258 my $fh_output = 'print $OFH ';
496 151         148 my $output = $string_output;
497 151         335 my $out_fh = $self->get_out_fh;
498 151 100       268 if ($out_fh) {
499 7         9 $output = $fh_output;
500             }
501 151         235 my @outputs = ($output);
502 151         163 my $warnings_string = "no warnings;\n";
503 151 100       353 if (my $warnings = $self->get_warnings) {
504 4 100       11 if ($warnings eq 1) {
    50          
505 2         2 $warnings_string = "use warnings;\n";
506             }
507             elsif ($warnings eq 'fatal') {
508 2         3 $warnings_string = "use warnings FATAL => qw(all);\n";
509             }
510             }
511 151         471 my $OPT_IS_OBJECT = $self->get_optimize->{object_check};
512 151         272 my $OPT_ROOT_HASH = $self->get_optimize->{root_hash};
513 151         386 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       268 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         151 my @lexicals;
539             my @switches;
540 151         325 my $tags = $class->get_tags;
541 151         354 my $meth = $self->method_call;
542 151         349 my $deref = $self->deref;
543 151         347 my $format = $self->formatter_path;
544 151         394 $class->init_name_re(
545             deref => $deref,
546             method_call => $meth,
547             formatter_path => $format,
548             );
549 151         476 my %var_args = (
550             deref => $deref,
551             method_call => $meth,
552             formatter_path => $format,
553             lexicals => \@lexicals,
554             );
555 151         159 my %use_vars;
556             my @wrapped;
557 151         153 my $globalstack = '';
558 151 100       439 if ($self->get_global_vars) {
559 8         10 $globalstack = '$new->set_globalstack($t->get_globalstack);';
560             }
561 151         345 my $line_info = $self->get_line_info;
562 151         329 for my $token (@p) {
563 1026 100       1926 @use_vars{ @lexicals } = () if @lexicals;
564 1026         2366 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         1402 my $indent = INDENT x $nlevel;
568 1026 100       1315 $code .= "#line $line $fname\n" if $line_info;
569 1026 100       2359 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         608 local $Data::Dumper::Deparse = 1;
575              
576 541 100       1621 if ($text =~ m/\A(?:\r?\n|\r)\z/) {
577 223         251 $text =~ s/\r/\\r/;
578 223         381 $text =~ s/\n/\\n/;
579 223         739 $code .= qq#$indent$output "$text";# . $/;
580             }
581             else {
582 318         660 $code .= qq#$indent$output # . $class->dump_string($text) . ';' . $/;
583             }
584             }
585             }
586             elsif ($token->is_open) {
587             # --------- TMPL_VAR
588 383 100       846 if ($tname eq T_VAR) {
    100          
    100          
589 235         304 my $var = $attr->{NAME};
590 235 100       502 if ($self->get_use_query) {
591 28         119 $info_stack->[-1]->{lc $var}->{type} = T_VAR;
592             }
593 235         210 my $expr;
594 235 50 33     666 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         1107 $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         12 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       120 $perl =~ s/($re)/exists $map{$1} ? $map{$1} : $1/eg;
  9         30  
622 4         15 $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         54 );
635 13         32 $code .= <<"EOM";
636             ${indent}\{
637             EOM
638 13 100       687 if ($self->get_global_vars) {
639 5         16 $code .= _expr_method(
640             'pushGlobalstack',
641             '$t', '$$C'
642             )->to_string($nlevel) . ";\n";
643             }
644 13         45 $code .= <<"EOM";
645             ${indent} my \$C = \\$varstr;
646             ${indent} if (defined \$\$C) {
647             EOM
648 13 50       31 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     4741 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         8 my $var = $attr->{NAME};
675 4 100       10 if ($var =~ tr/a-zA-Z0-9_//c) {
676 1         4 $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         4 my $value;
687             my $expr;
688 3 50       6 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         14 $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     155 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         213 ccontext => $ccontext,
729             );
730 52         101 my $ind = INDENT;
731 52 100       112 if ($self->get_use_query) {
732 13         39 $info_stack->[-1]->{lc $var}->{type} = $tname;
733 13   100     41 $info_stack->[-1]->{lc $var}->{children} ||= {};
734 13         28 push @$info_stack, $info_stack->[-1]->{lc $var}->{children};
735             }
736 52         69 my $lexical = $attr->{ALIAS};
737 52         46 my $insert_break = '';
738 52 100       110 if (defined (my $break = $attr->{BREAK})) {
739 1         2 $break =~ tr/0-9//cd;
740 1 50       2 if ($break) {
741 1         2 $insert_break = qq#local \$__break__ = ! ((\$__ix__+1 ) \% $break);#;
742             }
743             }
744 52         62 push @lexicals, $lexical;
745 52         50 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         49 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         6 context => $token,
757             compiler => $class,
758             );
759 2         4 ($sort_key_a, $sort_key_b) = ($varstr, $varstr);
760 2         7 $sort_key_a =~ s/\$\$C/\$hash\{\$a\}/g;
761 2         4 $sort_key_b =~ s/\$\$C/\$hash\{\$b\}/g;
762             }
763              
764 52 100       90 if ($attr->{REVERSE}) {
765 1         3 ($sort_key_b, $sort_key_a) = ($sort_key_a, $sort_key_b);
766             }
767 52         53 my $sort_op = 'cmp';
768 52 100 100     162 if (!defined $attr->{SORT} or uc $attr->{SORT} eq 'ALPHA') {
    50          
769             }
770             elsif (uc $attr->{SORT} eq 'NUM') {
771 2         4 $sort_op = '<=>';
772             }
773 52         96 $sort_keys = "sort \{ $sort_key_a $sort_op $sort_key_b \}";
774              
775 52         49 my $global = '';
776 52 100       93 my $lexi =
777             defined $lexical ? "${indent}local \$HTML::Template::Compiled::_lexi_$lexical = \$\$C;\n" : "";
778 52 100       99 if ($self->get_global_vars) {
779 3         11 my $pop_global = _expr_method(
780             'pushGlobalstack',
781             '$t', '$$C'
782             );
783 3         9 $global = $pop_global->to_string($nlevel).";\n";
784              
785             }
786 52 100       146 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         39 $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         48 my $join_code = '';
818 44 100       83 if (defined (my $join = $attr->{JOIN})) {
819 2         6 my $dump = HTML::Template::Compiled->dump_var($join, 'join');
820 2         93 $dump =~ s{\$join *= *}{};
821 2         5 $dump =~ s{;$}{};
822 2         5 $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         212 $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       130 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         5 my $exp = "\} else \{";
855 5         8 $code .= $exp;
856             }
857              
858             # --------- TMPL_IF TMPL_UNLESS TMPL_ELSIF TMPL_IF_DEFINED
859             elsif ($tname eq T_IF) {
860 19         81 my $expr = $class->_compile_OPEN_IF($self, {
861             %var_args,
862             context => $token,
863             },);
864 19         57 $code .= $expr;
865             }
866             elsif ($tname eq T_IF_DEFINED) {
867 4         17 my $expr = $class->_compile_OPEN_IF_DEFINED($self, {
868             %var_args,
869             context => $token,
870             },);
871 4         11 $code .= $expr;
872             }
873             elsif ($tname eq T_UNLESS) {
874 2         9 my $expr = $class->_compile_OPEN_UNLESS($self, {
875             %var_args,
876             context => $token,
877             },);
878 2         6 $code .= $expr;
879             }
880              
881             # --------- TMPL_ELSIF
882             elsif ($tname eq T_ELSIF) {
883 7         21 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         29 );
891 7         30 my $operand = _expr_literal($varstr);
892 7         20 my $exp = _expr_elsif($operand);
893 7         21 my $str = $exp->to_string($nlevel);
894 7         57 $code .= $str . $/;
895             }
896              
897             # --------- TMPL_SWITCH
898             elsif ($tname eq T_SWITCH) {
899 3         4 my $var = $attr->{NAME};
900 3         3 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         12 );
908 3         12 $code .= <<"EOM";
909             ${indent}SWITCH: for my \$_switch ($varstr) \{
910             EOM
911             }
912            
913             # --------- TMPL_CASE
914             elsif ($tname eq T_CASE) {
915 5         7 my $val = $attr->{NAME};
916             #$val =~ s/^\s+//;
917 5 100       7 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         4 $switches[$#switches] = 1;
924             }
925 5 100 66     16 if ( !length $val or uc $val eq 'DEFAULT' ) {
926 1         4 $code .= qq#${indent}if (1) \{\n#;
927             }
928             else {
929 4         5 $val =~ tr/'//d;
930 4         8 my @splitted = split /,/, $val;
931 4         5 my $is_default = '';
932             @splitted = grep {
933 4         4 uc $_ eq 'DEFAULT'
934 6 100       13 ? do {
935 1         1 $is_default = ' or 1 ';
936 1         2 0;
937             }
938             : 1
939             } @splitted;
940 4         7 my $values = join ",", map { qq#'$_'# } @splitted;
  5         9  
941 4 100 100     12 if ($is_default or @splitted > 1) {
942 2         12 $code .=
943             qq#${indent}if (grep \{ \$_switch eq \$_ \} $values $is_default) \{\n#;
944             }
945             else {
946 2         10 $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         2 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         4 $code .= <<"EOM";
964             \{
965             my \$scalar = $varstr;
966             my \$new = \$t->new_scalar_from_object(\$scalar);
967             $globalstack
968 1 50       6 $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         32 my $filename;
977             my $varstr;
978 26         64 my $path = $self->get_path();
979 26         27 my $dir;
980 26 100       58 my $dynamic = $tname eq T_INCLUDE_VAR ? 1 : 0;
981 26         31 my $fullpath = "''";
982              
983 26         24 my $cwd;
984 26 100       55 unless ($self->get_scalar) {
985 22         782 $dir = dirname($fname);
986 22 100       69 if ($self->get_search_path == 1) {
    100          
987             }
988             elsif ($self->get_search_path == 2) {
989 2         3 $cwd = $dir;
990             }
991             else {
992 16         31 $path = [ $dir ] ;
993             }
994             }
995 26 100       52 if ($dynamic) {
996             # dynamic filename
997 1         2 my $dfilename = $attr->{NAME};
998 1 50       2 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         5 );
1008             }
1009             else {
1010             # static filename
1011 25         50 $filename = $attr->{NAME};
1012 25         110 $fullpath = $self->createFilename( [@$path], \$filename, $cwd );
1013 24 100       71 if ($self->get_use_query) {
1014 3         11 $info_stack->[-1]->{lc $filename}->{type} = $tname;
1015             }
1016 24         84 $varstr = $self->quote_file($filename);
1017             # generate included template
1018             {
1019 24         28 D && $self->log("compile include $filename!!");
  24         20  
1020 24         50 my $recursed = ++$HTML::Template::Compiled::COMPILE_STACK{$fullpath};
1021 24 100       62 if ($recursed <= 1) {
1022 23         22 my $cached_or_new;
1023 23 50       66 $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         81 $self->get_includes()->{$fullpath}
1029             = [$path, $filename, $cached_or_new];
1030             }
1031 24         53 --$HTML::Template::Compiled::COMPILE_STACK{$fullpath};
1032 24         63 $fullpath = $self->quote_file($fullpath);
1033             }
1034             }
1035             #print STDERR "include $varstr\n";
1036 25         58 my $cache = $self->get_cache_dir;
1037             $path = defined $path
1038             ? '['
1039 25 50       86 . join( ',', map { $self->quote_file($_) } @$path ) . ']'
  27         61  
1040             : 'undef';
1041 25 100       65 $cwd = defined $cwd ? $self->quote_file($cwd) : 'undef';
1042 25 100       59 $cache = defined $cache ? $self->quote_file($cache) : 'undef';
1043 25 100       77 if ($dynamic) {
    100          
1044 1         8 $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       8 $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         12 push @outputs, '$OUT' . (1 + scalar @outputs) . ' .= ';
1066 6         6 $output = $outputs[-1];
1067 6         5 my $wrapped = '';
1068 6         4 $code .= <<"EOM";
1069             # ---------- WRAPPER
1070             \{
1071 6         14 my \$OUT@{[ scalar @outputs ]};
1072             EOM
1073 6         6 my $argument_fh = 'undef';
1074 6 100       9 if ($out_fh) {
1075 3         3 $wrapped .= <<"EOM";
1076             my \$tmp_var = '';
1077             open my \$tmp_fh, '>', \\\$tmp_var;
1078             EOM
1079 3         3 $argument_fh = "\$tmp_fh";
1080             }
1081 6         6 $wrapped .= <<"EOM";
1082 6         25 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         11 \$OUT@{[ scalar @outputs ]} = '';
1095             EOM
1096 6 100       10 if ($out_fh) {
1097 3         5 $wrapped .= <<"EOM";
1098             $outputs[-2] \$tmp_var;
1099             EOM
1100             }
1101 6         4 $wrapped .= <<"EOM";
1102             \}
1103             EOM
1104 6         15 push @wrapped, $wrapped;
1105             }
1106             else {
1107 18         113 $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       162 $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         288 my $subs = $tags->{$tname};
1130 255 50 66     666 if ($subs && $subs->{open}) {
1131 3         12 $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     501 if ($tname =~ m/^(?:IF|UNLESS|WITH|IF_DEFINED)$/) {
    100 100        
    100          
    50          
1140 38         54 my $var = $attr->{NAME};
1141 38 100       85 $var = '' unless defined $var;
1142             #print STDERR "============ IF ($text)\n";
1143 38         36 $code .= "\}" ;
1144 38 100 100     79 if ($self->get_global_vars && $tname eq 'WITH') {
1145 5         9 $code .= qq{\n} . $indent . qq#\$t->popGlobalstack;\n#;
1146             }
1147 38 100       105 $code .= ($tname eq 'WITH' ? "\}" : '') . qq{\n};
1148             }
1149              
1150             # --------- / TMPL_SWITCH
1151             elsif ($tname eq T_SWITCH) {
1152 3 50       6 if ( $switches[$#switches] ) {
1153              
1154             # we had at least one CASE, so we close the last if
1155 3         4 $code .= "\} # last case\n";
1156             }
1157 3         4 $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         49 pop @lexicals;
1164 52 100       121 if ($self->get_use_query) {
1165 13         19 pop @$info_stack;
1166             }
1167 52         57 $code .= "\}";
1168 52 100       105 if ($self->get_global_vars) {
1169 3         9 $code .= qq{\n} . $indent . qq#\$t->popGlobalstack;\n#;
1170             }
1171 52         106 $code .= "\} # end loop\n";
1172             }
1173             elsif ($tname eq T_WRAPPER) {
1174 6         14 $code .= $wrapped[-1];
1175 6         6 pop @wrapped;
1176 6         6 pop @outputs;
1177 6         7 $output = $outputs[-1];
1178 6         9 $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       392 if ($self->get_use_query) {
1196 10         44 $self->set_parse_tree($info);
1197             }
1198 149         372 my @use_vars = grep length, keys %use_vars;
1199 149 100       273 if (@use_vars) {
1200             # $header .= qq#use vars qw/ @{[ map { '$_lexi_'.$_ } @use_vars ]} /;\n#;
1201             }
1202             #warn Data::Dumper->Dump([\$info], ['info']);
1203 149         179 $code .= qq#return \$OUT;\n#;
1204 149         425 $code = $header . $code . "\n} # end of sub\n";
1205              
1206             #$code .= "\n} # end of sub\n";
1207 149 50       329 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       503 if ( $code =~ m/(\A.*\z)/ms ) {
1211             # we trust our template
1212 149         359 $code = $1;
1213             }
1214             else {
1215 0         0 $code = "";
1216             }
1217 149         181 my $l = length $code;
1218             #print STDERR "length $fname: $l\n";
1219 36     36   186 my $sub = eval $code;
  36     36   43  
  36     36   2356  
  36     25   140  
  36     24   40  
  36     24   776  
  36     20   111  
  36     19   37  
  36     19   5647  
  25     15   964  
  25     14   547  
  25     14   1597  
  24     12   93  
  24         27  
  24         499  
  24         73  
  24         32  
  24         3321  
  20         2247  
  20         1386  
  20         2561  
  19         67  
  19         24  
  19         509  
  19         63  
  19         21  
  19         1645  
  15         973  
  15         656  
  15         1627  
  14         59  
  14         17  
  14         471  
  14         45  
  14         16  
  14         1000  
  12         47  
  12         15  
  12         1372  
  149         12096  
1220             #die "code: $@ ($code)" if $@;
1221 149 50       453 die "code: $@" if $@;
1222 149         2280 return $code, $sub;
1223             }
1224             sub _compile_OPEN_VAR {
1225 235     235   435 my ($self, $htc, $args) = @_;
1226             #print STDERR "===== VAR ($text)\n";
1227 235         240 my $token = $args->{context};
1228 235         618 my $attr = $token->get_attributes;
1229 235         265 my $var = $attr->{NAME};
1230             #my $expr = $attr->{EXPR};
1231 235         188 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         836 );
1240              
1241             #print "line: $text var: $var ($varstr)\n";
1242 235         384 my $exp = $varstr;
1243             # ---- default
1244 235         194 my $default;
1245 235 100       439 if (defined $attr->{DEFAULT}) {
1246 4         12 $default = $self->dump_string($attr->{DEFAULT});
1247 4         16 $exp = _expr_ternary(
1248             _expr_defined($exp),
1249             $exp,
1250             $default,
1251             )->to_string;
1252             }
1253             # ---- escapes
1254 235         541 my $escape = $htc->get_default_escape;
1255 235 100       415 if (exists $attr->{ESCAPE}) {
1256 14         19 $escape = $attr->{ESCAPE};
1257             }
1258 235 100       361 $exp = $self->_escape_expression($exp, $escape) if $escape;
1259 235         436 return $exp;
1260             }
1261              
1262             sub _compile_OPEN_IF {
1263 19     19   19 my ($self, $htc, $args) = @_;
1264             #print STDERR "============ IF ($text)\n";
1265 19         55 my $var = $args->{context}->get_attributes->{NAME};
1266 19         20 my $token = $args->{context};
1267 19         31 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         64 );
1274 19         70 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         5 my $var = $args->{context}->get_attributes->{NAME};
1280 2         2 my $token = $args->{context};
1281 2         4 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         7 );
1288 2         8 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         13 my $var = $args->{context}->get_attributes->{NAME};
1294 4         5 my $token = $args->{context};
1295 4         5 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         16 );
1302 4         11 return "if (defined ($varstr)) \{";
1303             }
1304              
1305             1;
1306              
1307             __END__