File Coverage

lib/Template/Parser.pm
Criterion Covered Total %
statement 299 320 93.4
branch 148 176 84.0
condition 43 61 70.4
subroutine 29 30 96.6
pod 2 16 12.5
total 521 603 86.4


line stmt bran cond sub pod time code
1             #============================================================= -*-Perl-*-
2             #
3             # Template::Parser
4             #
5             # DESCRIPTION
6             # This module implements a LALR(1) parser and associated support
7             # methods to parse template documents into the appropriate "compiled"
8             # format. Much of the parser DFA code (see _parse() method) is based
9             # on Francois Desarmenien's Parse::Yapp module. Kudos to him.
10             #
11             # AUTHOR
12             # Andy Wardley
13             #
14             # COPYRIGHT
15             # Copyright (C) 1996-2007 Andy Wardley. All Rights Reserved.
16             #
17             # This module is free software; you can redistribute it and/or
18             # modify it under the same terms as Perl itself.
19             #
20             # The following copyright notice appears in the Parse::Yapp
21             # documentation.
22             #
23             # The Parse::Yapp module and its related modules and shell
24             # scripts are copyright (c) 1998 Francois Desarmenien,
25             # France. All rights reserved.
26             #
27             # You may use and distribute them under the terms of either
28             # the GNU General Public License or the Artistic License, as
29             # specified in the Perl README file.
30             #
31             #============================================================================
32              
33             package Template::Parser;
34              
35 80     80   11579 use strict;
  80         173  
  80         3685  
36 80     80   690 use warnings;
  80         156  
  80         4696  
37 80     80   499 use base 'Template::Base';
  80         161  
  80         8295  
38              
39 80     80   540 use Template::Constants qw( :status :chomp );
  80         157  
  80         22253  
40 80     80   51924 use Template::Directive;
  80         275  
  80         3047  
41 80     80   91271 use Template::Grammar;
  80         105310  
  80         15113  
42              
43             # parser state constants
44 80     80   973 use constant CONTINUE => 0;
  80         193  
  80         6284  
45 80     80   454 use constant ACCEPT => 1;
  80         175  
  80         3768  
46 80     80   479 use constant ERROR => 2;
  80         185  
  80         3196  
47 80     80   454 use constant ABORT => 3;
  80         314  
  80         490136  
48              
49             our $VERSION = 2.89;
50             our $DEBUG = 0 unless defined $DEBUG;
51             our $ERROR = '';
52              
53              
54             #========================================================================
55             # -- COMMON TAG STYLES --
56             #========================================================================
57              
58             our $TAG_STYLE = {
59             'default' => [ '\[%', '%\]' ],
60             'template1' => [ '[\[%]%', '%[\]%]' ],
61             'metatext' => [ '%%', '%%' ],
62             'html' => [ '' ],
63             'mason' => [ '<%', '>' ],
64             'asp' => [ '<%', '%>' ],
65             'php' => [ '<\?', '\?>' ],
66             'star' => [ '\[\*', '\*\]' ],
67             };
68             $TAG_STYLE->{ template } = $TAG_STYLE->{ tt2 } = $TAG_STYLE->{ default };
69              
70              
71             our $DEFAULT_STYLE = {
72             START_TAG => $TAG_STYLE->{ default }->[0],
73             END_TAG => $TAG_STYLE->{ default }->[1],
74             # TAG_STYLE => 'default',
75             ANYCASE => 0,
76             INTERPOLATE => 0,
77             PRE_CHOMP => 0,
78             POST_CHOMP => 0,
79             V1DOLLAR => 0,
80             EVAL_PERL => 0,
81             };
82              
83             our $QUOTED_ESCAPES = {
84             n => "\n",
85             r => "\r",
86             t => "\t",
87             };
88              
89             # note that '-' must come first so Perl doesn't think it denotes a range
90             our $CHOMP_FLAGS = qr/[-=~+]/;
91              
92              
93              
94             #========================================================================
95             # ----- PUBLIC METHODS -----
96             #========================================================================
97              
98             #------------------------------------------------------------------------
99             # new(\%config)
100             #
101             # Constructor method.
102             #------------------------------------------------------------------------
103              
104             sub new {
105 133     133 1 394 my $class = shift;
106 133 100 66     1513 my $config = $_[0] && ref($_[0]) eq 'HASH' ? shift(@_) : { @_ };
107 133         339 my ($tagstyle, $debug, $start, $end, $defaults, $grammar, $hash, $key, $udef);
108              
109             my $self = bless {
110             START_TAG => undef,
111             END_TAG => undef,
112             TAG_STYLE => 'default',
113             ANYCASE => 0,
114             INTERPOLATE => 0,
115             PRE_CHOMP => 0,
116             POST_CHOMP => 0,
117             V1DOLLAR => 0,
118             EVAL_PERL => 0,
119             FILE_INFO => 1,
120             GRAMMAR => undef,
121             _ERROR => '',
122             IN_BLOCK => [ ],
123             TRACE_VARS => $config->{ TRACE_VARS },
124 133   100     5778 FACTORY => $config->{ FACTORY } || 'Template::Directive',
125             }, $class;
126              
127             # update self with any relevant keys in config
128 133         1492 foreach $key (keys %$self) {
129 1995 100       4435 $self->{ $key } = $config->{ $key } if defined $config->{ $key };
130             }
131 133         729 $self->{ FILEINFO } = [ ];
132            
133             # DEBUG config item can be a bitmask
134 133 100       1588 if (defined ($debug = $config->{ DEBUG })) {
    50          
135 15         42 $self->{ DEBUG } = $debug & ( Template::Constants::DEBUG_PARSER
136             | Template::Constants::DEBUG_FLAGS );
137 15         41 $self->{ DEBUG_DIRS } = $debug & Template::Constants::DEBUG_DIRS;
138             }
139             # package variable can be set to 1 to support previous behaviour
140             elsif ($DEBUG == 1) {
141 0         0 $self->{ DEBUG } = Template::Constants::DEBUG_PARSER;
142 0         0 $self->{ DEBUG_DIRS } = 0;
143             }
144             # otherwise let $DEBUG be a bitmask
145             else {
146 118         557 $self->{ DEBUG } = $DEBUG & ( Template::Constants::DEBUG_PARSER
147             | Template::Constants::DEBUG_FLAGS );
148 118         421 $self->{ DEBUG_DIRS } = $DEBUG & Template::Constants::DEBUG_DIRS;
149             }
150              
151 133   33     2955 $grammar = $self->{ GRAMMAR } ||= do {
152 133         1186 require Template::Grammar;
153 133         1100 Template::Grammar->new();
154             };
155              
156             # instantiate a FACTORY object
157 133 100       662 unless (ref $self->{ FACTORY }) {
158 132         337 my $fclass = $self->{ FACTORY };
159             $self->{ FACTORY } = $self->{ FACTORY }->new(
160             NAMESPACE => $config->{ NAMESPACE }
161             )
162 132   50     1870 || return $class->error($self->{ FACTORY }->error());
163             }
164            
165             # load grammar rules, states and lex table
166 133         1000 @$self{ qw( LEXTABLE STATES RULES ) }
167             = @$grammar{ qw( LEXTABLE STATES RULES ) };
168            
169 133 50       764 $self->new_style($config)
170             || return $class->error($self->error());
171            
172 133         1574 return $self;
173             }
174              
175             #-----------------------------------------------------------------------
176             # These methods are used to track nested IF and WHILE blocks. Each
177             # generated if/while block is given a label indicating the directive
178             # type and nesting depth, e.g. FOR0, WHILE1, FOR2, WHILE3, etc. The
179             # NEXT and LAST directives use the innermost label, e.g. last WHILE3;
180             #-----------------------------------------------------------------------
181              
182             sub enter_block {
183 130     130 0 764 my ($self, $name) = @_;
184 130         360 my $blocks = $self->{ IN_BLOCK };
185 130         194 push(@{ $self->{ IN_BLOCK } }, $name);
  130         484  
186             }
187              
188             sub leave_block {
189 130     130 0 1052 my $self = shift;
190 130         480 my $label = $self->block_label;
191 130         418 pop(@{ $self->{ IN_BLOCK } });
  130         271  
192 130         1244 return $label;
193             }
194              
195             sub in_block {
196 17     17 0 113 my ($self, $name) = @_;
197 17         42 my $blocks = $self->{ IN_BLOCK };
198 17   100     118 return @$blocks && $blocks->[-1] eq $name;
199             }
200              
201             sub block_label {
202 158     158 0 402 my ($self, $prefix, $suffix) = @_;
203 158         322 my $blocks = $self->{ IN_BLOCK };
204 158 100       569 my $name = @$blocks
205             ? $blocks->[-1] . scalar @$blocks
206             : undef;
207 158         282 return join('', grep { defined $_ } $prefix, $name, $suffix);
  474         1366  
208             }
209              
210              
211              
212             #------------------------------------------------------------------------
213             # new_style(\%config)
214             #
215             # Install a new (stacked) parser style. This feature is currently
216             # experimental but should mimic the previous behaviour with regard to
217             # TAG_STYLE, START_TAG, END_TAG, etc.
218             #------------------------------------------------------------------------
219              
220             sub new_style {
221 134     134 0 384 my ($self, $config) = @_;
222 134   100     996 my $styles = $self->{ STYLE } ||= [ ];
223 134         317 my ($tagstyle, $tags, $start, $end, $key);
224              
225             # clone new style from previous or default style
226 134 100       268 my $style = { %{ $styles->[-1] || $DEFAULT_STYLE } };
  134         2236  
227              
228             # expand START_TAG and END_TAG from specified TAG_STYLE
229 134 100       901 if ($tagstyle = $config->{ TAG_STYLE }) {
230 3 50       14 return $self->error("Invalid tag style: $tagstyle")
231             unless defined ($tags = $TAG_STYLE->{ $tagstyle });
232 3         9 ($start, $end) = @$tags;
233 3   33     25 $config->{ START_TAG } ||= $start;
234 3   33     172 $config->{ END_TAG } ||= $end;
235             }
236              
237 134         577 foreach $key (keys %$DEFAULT_STYLE) {
238 1072 100       2559 $style->{ $key } = $config->{ $key } if defined $config->{ $key };
239             }
240 134         439 push(@$styles, $style);
241 134         568 return $style;
242             }
243              
244              
245             #------------------------------------------------------------------------
246             # old_style()
247             #
248             # Pop the current parser style and revert to the previous one. See
249             # new_style(). ** experimental **
250             #------------------------------------------------------------------------
251              
252             sub old_style {
253 1     1 0 7 my $self = shift;
254 1         2 my $styles = $self->{ STYLE };
255 1 50       4 return $self->error('only 1 parser style remaining')
256             unless (@$styles > 1);
257 1         2 pop @$styles;
258 1         2 return $styles->[-1];
259             }
260              
261              
262             #------------------------------------------------------------------------
263             # parse($text, $data)
264             #
265             # Parses the text string, $text and returns a hash array representing
266             # the compiled template block(s) as Perl code, in the format expected
267             # by Template::Document.
268             #------------------------------------------------------------------------
269              
270             sub parse {
271 1281     1281 1 2535 my ($self, $text, $info) = @_;
272 1281         1790 my ($tokens, $block);
273              
274             $info->{ DEBUG } = $self->{ DEBUG_DIRS }
275 1281 50       6783 unless defined $info->{ DEBUG };
276              
277             # print "info: { ", join(', ', map { "$_ => $info->{ $_ }" } keys %$info), " }\n";
278              
279             # store for blocks defined in the template (see define_block())
280 1281         3473 my $defblock = $self->{ DEFBLOCK } = { };
281 1281         6797 my $metadata = $self->{ METADATA } = [ ];
282 1281         3507 my $variables = $self->{ VARIABLES } = { };
283 1281         4044 $self->{ DEFBLOCKS } = [ ];
284              
285 1281         3257 $self->{ _ERROR } = '';
286              
287             # split file into TEXT/DIRECTIVE chunks
288 1281   50     4163 $tokens = $self->split_text($text)
289             || return undef; ## RETURN ##
290              
291 1281         2189 push(@{ $self->{ FILEINFO } }, $info);
  1281         3334  
292              
293             # parse chunks
294 1281         5320 $block = $self->_parse($tokens, $info);
295              
296 1281         2794 pop(@{ $self->{ FILEINFO } });
  1281         3508  
297              
298 1281 100       3582 return undef unless $block; ## RETURN ##
299              
300             $self->debug("compiled main template document block:\n$block")
301 1278 50       4706 if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER;
302              
303             return {
304 1278         14824 BLOCK => $block,
305             DEFBLOCKS => $defblock,
306             VARIABLES => $variables,
307             METADATA => { @$metadata },
308             };
309             }
310              
311              
312              
313             #------------------------------------------------------------------------
314             # split_text($text)
315             #
316             # Split input template text into directives and raw text chunks.
317             #------------------------------------------------------------------------
318              
319             sub split_text {
320 1281     1281 0 2566 my ($self, $text) = @_;
321 1281         1983 my ($pre, $dir, $prelines, $dirlines, $postlines, $chomp, $tags, @tags);
322 1281         3332 my $style = $self->{ STYLE }->[-1];
323 1281         5370 my ($start, $end, $prechomp, $postchomp, $interp ) =
324             @$style{ qw( START_TAG END_TAG PRE_CHOMP POST_CHOMP INTERPOLATE ) };
325 1281 100       8533 my $tags_dir = $self->{ANYCASE} ? qri : qr;
326              
327 1281         2690 my @tokens = ();
328 1281         2163 my $line = 1;
329              
330             return \@tokens ## RETURN ##
331 1281 100 66     7561 unless defined $text && length $text;
332              
333             # extract all directives from the text
334 1274         20937 while ($text =~ s/
335             ^(.*?) # $1 - start of line up to directive
336             (?:
337             $start # start of tag
338             (.*?) # $2 - tag contents
339             $end # end of tag
340             )
341             //sx) {
342            
343 3753         22026 ($pre, $dir) = ($1, $2);
344 3753 50       9113 $pre = '' unless defined $pre;
345 3753 50       8458 $dir = '' unless defined $dir;
346            
347 3753         6124 $prelines = ($pre =~ tr/\n//); # newlines in preceding text
348 3753         6190 $dirlines = ($dir =~ tr/\n//); # newlines in directive tag
349 3753         5372 $postlines = 0; # newlines chomped after tag
350            
351 3753         8889 for ($dir) {
352 3753 100       9030 if (/^\#/) {
353             # comment out entire directive except for any end chomp flag
354 11 100       229 $dir = ($dir =~ /($CHOMP_FLAGS)$/o) ? $1 : '';
355             }
356             else {
357              
358 3742 100 33     33796 if(s/^($CHOMP_FLAGS)?(\s*)//so && $2) {
359 3732         6542 my $chomped = $2;
360 3732         5396 my $linecount = ($chomped =~ tr/\n//); # newlines in chomped whitespace
361 3732   100     14107 $linecount ||= 0;
362 3732         4599 $prelines += $linecount;
363 3732         6316 $dirlines -= $linecount;
364             }
365             # PRE_CHOMP: process whitespace before tag
366 3742 100       10267 $chomp = $1 ? $1 : $prechomp;
367 3742         5710 $chomp =~ tr/-=~+/1230/;
368 3742 100 100     10636 if ($chomp && $pre) {
369             # chomp off whitespace and newline preceding directive
370 118 100       546 if ($chomp == CHOMP_ALL) {
    100          
    50          
371 109         1151 $pre =~ s{ (\r?\n|^) [^\S\n]* \z }{}mx;
372             }
373             elsif ($chomp == CHOMP_COLLAPSE) {
374 6         32 $pre =~ s{ (\s+) \z }{ }x;
375             }
376             elsif ($chomp == CHOMP_GREEDY) {
377 3         13 $pre =~ s{ (\s+) \z }{}x;
378             }
379             }
380             }
381            
382             # POST_CHOMP: process whitespace after tag
383 3753         58768 s/\s*($CHOMP_FLAGS)?\s*$//so;
384 3753 100       9984 $chomp = $1 ? $1 : $postchomp;
385 3753         5390 $chomp =~ tr/-=~+/1230/;
386 3753 100       11608 if ($chomp) {
387 1840 100       5249 if ($chomp == CHOMP_ALL) {
    100          
    50          
388 1831 100       32760 $text =~ s{ ^ ([^\S\n]* \n) }{}x
389             && $postlines++;
390             }
391             elsif ($chomp == CHOMP_COLLAPSE) {
392 6 50       39 $text =~ s{ ^ (\s+) }{ }x
393             && ($postlines += $1=~y/\n//);
394             }
395             # any trailing whitespace
396             elsif ($chomp == CHOMP_GREEDY) {
397 3 50       18 $text =~ s{ ^ (\s+) }{}x
398             && ($postlines += $1=~y/\n//);
399             }
400             }
401             }
402            
403             # any text preceding the directive can now be added
404 3753 100       10244 if (length $pre) {
405 2075 100       7044 push(@tokens, $interp
406             ? [ $pre, $line, 'ITEXT' ]
407             : ('TEXT', $pre) );
408             }
409 3753         7435 $line += $prelines;
410            
411             # and now the directive, along with line number information
412 3753 100       8519 if (length $dir) {
413             # the TAGS directive is a compile-time switch
414 3738 100       19347 if ($dir =~ /^$tags_dir\s+(.*)/) {
415 15         137 my @tags = split(/\s+/, $1);
416 15 100       168 if (scalar @tags > 1) {
    50          
417 7         15 ($start, $end) = map { quotemeta($_) } @tags;
  14         67  
418             }
419             elsif ($tags = $TAG_STYLE->{ $tags[0] }) {
420 8         32 ($start, $end) = @$tags;
421             }
422             else {
423 0         0 warn "invalid TAGS style: $tags[0]\n";
424             }
425             }
426             else {
427             # DIRECTIVE is pushed as:
428             # [ $dirtext, $line_no(s), \@tokens ]
429 3723 100       14311 push(@tokens,
430             [ $dir,
431             ($dirlines
432             ? sprintf("%d-%d", $line, $line + $dirlines)
433             : $line),
434             $self->tokenise_directive($dir) ]);
435             }
436             }
437            
438             # update line counter to include directive lines and any extra
439             # newline chomped off the start of the following text
440 3753         38448 $line += $dirlines + $postlines;
441             }
442            
443             # anything remaining in the string is plain text
444 1274 100       6334 push(@tokens, $interp
    100          
445             ? [ $text, $line, 'ITEXT' ]
446             : ( 'TEXT', $text) )
447             if length $text;
448            
449 1274         7607 return \@tokens; ## RETURN ##
450             }
451            
452              
453              
454             #------------------------------------------------------------------------
455             # interpolate_text($text, $line)
456             #
457             # Examines $text looking for any variable references embedded like
458             # $this or like ${ this }.
459             #------------------------------------------------------------------------
460              
461             sub interpolate_text {
462 899     899 0 3605 my ($self, $text, $line) = @_;
463 899         1552 my @tokens = ();
464 899         1111 my ($pre, $var, $dir);
465              
466              
467 899         6469 while ($text =~
468             /
469             ( (?: \\. | [^\$] ){1,3000} ) # escaped or non-'$' character [$1]
470             |
471             ( \$ (?: # embedded variable [$2]
472             (?: \{ ([^\}]*) \} ) # ${ ... } [$3]
473             |
474             ([\w\.]+) # $word [$4]
475             )
476             )
477             /gx) {
478              
479 1399   66     6328 ($pre, $var, $dir) = ($1, $3 || $4, $2);
480              
481             # preceding text
482 1399 100 66     6007 if (defined($pre) && length($pre)) {
483 1090         2038 $line += $pre =~ tr/\n//;
484 1090         2058 $pre =~ s/\\\$/\$/g;
485 1090         2687 push(@tokens, 'TEXT', $pre);
486             }
487             # $variable reference
488 1399 100       5611 if ($var) {
    50          
489 309         1169 $line += $dir =~ tr/\n/ /;
490 309         1042 push(@tokens, [ $dir, $line, $self->tokenise_directive($var) ]);
491             }
492             # other '$' reference - treated as text
493             elsif ($dir) {
494 0         0 $line += $dir =~ tr/\n//;
495 0         0 push(@tokens, 'TEXT', $dir);
496             }
497             }
498              
499 899         4339 return \@tokens;
500             }
501              
502              
503              
504             #------------------------------------------------------------------------
505             # tokenise_directive($text)
506             #
507             # Called by the private _parse() method when it encounters a DIRECTIVE
508             # token in the list provided by the split_text() or interpolate_text()
509             # methods. The directive text is passed by parameter.
510             #
511             # The method splits the directive into individual tokens as recognised
512             # by the parser grammar (see Template::Grammar for details). It
513             # constructs a list of tokens each represented by 2 elements, as per
514             # split_text() et al. The first element contains the token type, the
515             # second the token itself.
516             #
517             # The method tokenises the string using a complex (but fast) regex.
518             # For a deeper understanding of the regex magic at work here, see
519             # Jeffrey Friedl's excellent book "Mastering Regular Expressions",
520             # from O'Reilly, ISBN 1-56592-257-3
521             #
522             # Returns a reference to the list of chunks (each one being 2 elements)
523             # identified in the directive text. On error, the internal _ERROR string
524             # is set and undef is returned.
525             #------------------------------------------------------------------------
526              
527             sub tokenise_directive {
528 4032     4032 0 7476 my ($self, $text, $line) = @_;
529 4032         4759 my ($token, $uctoken, $type, $lookup);
530 4032         7680 my $lextable = $self->{ LEXTABLE };
531 4032         7393 my $style = $self->{ STYLE }->[-1];
532 4032         9844 my ($anycase, $start, $end) = @$style{ qw( ANYCASE START_TAG END_TAG ) };
533 4032         6174 my @tokens = ( );
534              
535 4032         31165 while ($text =~
536             /
537             # strip out any comments
538             (\#[^\n]*)
539             |
540             # a quoted phrase matches in $3
541             (["']) # $2 - opening quote, ' or "
542             ( # $3 - quoted text buffer
543             (?: # repeat group (no backreference)
544             \\\\ # an escaped backslash \\
545             | # ...or...
546             \\\2 # an escaped quote \" or \' (match $1)
547             | # ...or...
548             . # any other character
549             | \n
550             )*? # non-greedy repeat
551             ) # end of $3
552             \2 # match opening quote
553             |
554             # an unquoted number matches in $4
555             (-?\d+(?:\.\d+)?) # numbers
556             |
557             # filename matches in $5
558             ( \/?\w+(?:(?:\/|::?)\w*)+ | \/\w+)
559             |
560             # an identifier matches in $6
561             (\w+) # variable identifier
562             |
563             # an unquoted word or symbol matches in $7
564             ( [(){}\[\]:;,\/\\] # misc parenthesis and symbols
565             # | \-> # arrow operator (for future?)
566             | [+\-*] # math operations
567             | \$\{? # dollar with option left brace
568             | => # like '='
569             | [=!<>]?= | [!<>] # eqality tests
570             | &&? | \|\|? # boolean ops
571             | \.\.? # n..n sequence
572             | \S+ # something unquoted
573             ) # end of $7
574             /gmxo) {
575              
576             # ignore comments to EOL
577 17023 100       46451 next if $1;
578              
579             # quoted string
580 16999 100       83942 if (defined ($token = $3)) {
    100          
    100          
    100          
    50          
581             # double-quoted string may include $variable references
582 1359 100       3896 if ($2 eq '"') {
583 308 100       1358 if ($token =~ /[\$\\]/) {
584 172         304 $type = 'QUOTED';
585             # unescape " and \ but leave \$ escaped so that
586             # interpolate_text() doesn't incorrectly treat it
587             # as a variable reference
588             # $token =~ s/\\([\\"])/$1/g;
589 172         530 for ($token) {
590 172         547 s/\\([^\$nrt])/$1/g;
591 172         667 s/\\([nrt])/$QUOTED_ESCAPES->{ $1 }/ge;
  109         603  
592             }
593 172         602 push(@tokens, ('"') x 2,
594 172         446 @{ $self->interpolate_text($token) },
595             ('"') x 2);
596 172         1252 next;
597             }
598             else {
599 136         867 $type = 'LITERAL';
600 136         300 $token =~ s['][\\']g;
601 136         336 $token = "'$token'";
602             }
603             }
604             else {
605 1051         1455 $type = 'LITERAL';
606 1051         2197 $token = "'$token'";
607             }
608             }
609             # number
610             elsif (defined ($token = $4)) {
611 716         1090 $type = 'NUMBER';
612             }
613             elsif (defined($token = $5)) {
614 26         66 $type = 'FILENAME';
615             }
616             elsif (defined($token = $6)) {
617             # Fold potential keywords to UPPER CASE if the ANYCASE option is
618             # set, unless (we've got some preceding tokens and) the previous
619             # token is a DOT op. This prevents the 'last' in 'data.last'
620             # from being interpreted as the LAST keyword.
621 8699 100 66     26930 $uctoken =
622             ($anycase && (! @tokens || $tokens[-2] ne 'DOT'))
623             ? uc $token
624             : $token;
625 8699 100       25092 if (defined ($type = $lextable->{ $uctoken })) {
626 2228         3640 $token = $uctoken;
627             }
628             else {
629 6471         9803 $type = 'IDENT';
630             }
631             }
632             elsif (defined ($token = $7)) {
633             # reserved words may be in lower case unless case sensitive
634 6199 100       11280 $uctoken = $anycase ? uc $token : $token;
635 6199 50       18141 unless (defined ($type = $lextable->{ $uctoken })) {
636 0         0 $type = 'UNQUOTED';
637             }
638             }
639              
640 16827         144460 push(@tokens, $type, $token);
641              
642             # print(STDERR " +[ $type, $token ]\n")
643             # if $DEBUG;
644             }
645              
646             # print STDERR "tokenise directive() returning:\n [ @tokens ]\n"
647             # if $DEBUG;
648              
649 4032         28088 return \@tokens; ## RETURN ##
650             }
651              
652              
653             #------------------------------------------------------------------------
654             # define_block($name, $block)
655             #
656             # Called by the parser 'defblock' rule when a BLOCK definition is
657             # encountered in the template. The name of the block is passed in the
658             # first parameter and a reference to the compiled block is passed in
659             # the second. This method stores the block in the $self->{ DEFBLOCK }
660             # hash which has been initialised by parse() and will later be used
661             # by the same method to call the store() method on the calling cache
662             # to define the block "externally".
663             #------------------------------------------------------------------------
664              
665             sub define_block {
666 154     154 0 1924 my ($self, $name, $block) = @_;
667             my $defblock = $self->{ DEFBLOCK }
668 154   50     580 || return undef;
669              
670             $self->debug("compiled block '$name':\n$block")
671 154 50       559 if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER;
672              
673 154         523 $defblock->{ $name } = $block;
674            
675 154         379 return undef;
676             }
677              
678             sub push_defblock {
679 30     30 0 224 my $self = shift;
680 30   100     170 my $stack = $self->{ DEFBLOCK_STACK } ||= [];
681 30         87 push(@$stack, $self->{ DEFBLOCK } );
682 30         108 $self->{ DEFBLOCK } = { };
683             }
684              
685             sub pop_defblock {
686 30     30 0 196 my $self = shift;
687 30         77 my $defs = $self->{ DEFBLOCK };
688 30   50     110 my $stack = $self->{ DEFBLOCK_STACK } || return $defs;
689 30 50       129 return $defs unless @$stack;
690 30         74 $self->{ DEFBLOCK } = pop @$stack;
691 30         215 return $defs;
692             }
693              
694              
695             #------------------------------------------------------------------------
696             # add_metadata(\@setlist)
697             #------------------------------------------------------------------------
698              
699             sub add_metadata {
700 25     25 0 339 my ($self, $setlist) = @_;
701             my $metadata = $self->{ METADATA }
702 25   50     110 || return undef;
703              
704 25         73 push(@$metadata, @$setlist);
705            
706 25         65 return undef;
707             }
708              
709              
710             #------------------------------------------------------------------------
711             # location()
712             #
713             # Return Perl comment indicating current parser file and line
714             #------------------------------------------------------------------------
715              
716             sub location {
717 3456     3456 0 26394 my $self = shift;
718 3456 100       10017 return "\n" unless $self->{ FILE_INFO };
719 3443         3803 my $line = ${ $self->{ LINE } };
  3443         18307  
720 3443         7880 my $info = $self->{ FILEINFO }->[-1];
721             my $file = $info->{ path } || $info->{ name }
722 3443   100     10992 || '(unknown template)';
723 3443         9347 $line =~ s/\-.*$//; # might be 'n-n'
724 3443   100     7438 $line ||= 1;
725 3443         16842 return "#line $line \"$file\"\n";
726             }
727              
728              
729             #========================================================================
730             # ----- PRIVATE METHODS -----
731             #========================================================================
732              
733             #------------------------------------------------------------------------
734             # _parse(\@tokens, \@info)
735             #
736             # Parses the list of input tokens passed by reference and returns a
737             # Template::Directive::Block object which contains the compiled
738             # representation of the template.
739             #
740             # This is the main parser DFA loop. See embedded comments for
741             # further details.
742             #
743             # On error, undef is returned and the internal _ERROR field is set to
744             # indicate the error. This can be retrieved by calling the error()
745             # method.
746             #------------------------------------------------------------------------
747              
748             sub _parse {
749 1281     1281   2594 my ($self, $tokens, $info) = @_;
750 1281         2075 my ($token, $value, $text, $line, $inperl);
751 0         0 my ($state, $stateno, $status, $action, $lookup, $coderet, @codevars);
752 0         0 my ($lhs, $len, $code); # rule contents
753 1281         6824 my $stack = [ [ 0, undef ] ]; # DFA stack
754              
755             # DEBUG
756             # local $" = ', ';
757              
758             # retrieve internal rule and state tables
759 1281         4222 my ($states, $rules) = @$self{ qw( STATES RULES ) };
760              
761             # If we're tracing variable usage then we need to give the factory a
762             # reference to our $self->{ VARIABLES } for it to fill in. This is a
763             # bit of a hack to back-patch this functionality into TT2.
764             $self->{ FACTORY }->trace_vars($self->{ VARIABLES })
765 1281 50       4559 if $self->{ TRACE_VARS };
766              
767             # call the grammar set_factory method to install emitter factory
768 1281         7604 $self->{ GRAMMAR }->install_factory($self->{ FACTORY });
769              
770 1281         4677 $line = $inperl = 0;
771 1281         8159 $self->{ LINE } = \$line;
772 1281         3477 $self->{ FILE } = $info->{ name };
773 1281         2715 $self->{ INPERL } = \$inperl;
774              
775 1281         2159 $status = CONTINUE;
776 1281         1911 my $in_string = 0;
777              
778 1281         2071 while(1) {
779             # get state number and state
780 92331         164491 $stateno = $stack->[-1]->[0];
781 92331         134318 $state = $states->[$stateno];
782              
783             # see if any lookaheads exist for the current state
784 92331 100       198691 if (exists $state->{'ACTIONS'}) {
785              
786             # get next token and expand any directives (i.e. token is an
787             # array ref) onto the front of the token list
788 44028   100     190441 while (! defined $token && @$tokens) {
789 29503         48642 $token = shift(@$tokens);
790 29503 100       57964 if (ref $token) {
791 4770         13637 ($text, $line, $token) = @$token;
792 4770 100       14507 if (ref $token) {
    50          
793 4030 100 100     13933 if ($info->{ DEBUG } && ! $in_string) {
794             # - - - - - - - - - - - - - - - - - - - - - - - - -
795             # This is gnarly. Look away now if you're easily
796             # frightened. We're pushing parse tokens onto the
797             # pending list to simulate a DEBUG directive like so:
798             # [% DEBUG msg line='20' text='INCLUDE foo' %]
799             # - - - - - - - - - - - - - - - - - - - - - - - - -
800 15         19 my $dtext = $text;
801 15         25 $dtext =~ s[(['\\])][\\$1]g;
802 15         152 unshift(@$tokens,
803             DEBUG => 'DEBUG',
804             IDENT => 'msg',
805             IDENT => 'line',
806             ASSIGN => '=',
807             LITERAL => "'$line'",
808             IDENT => 'text',
809             ASSIGN => '=',
810             LITERAL => "'$dtext'",
811             IDENT => 'file',
812             ASSIGN => '=',
813             LITERAL => "'$info->{ name }'",
814             (';') x 2,
815             @$token,
816             (';') x 2);
817             }
818             else {
819 4015         27229 unshift(@$tokens, @$token, (';') x 2);
820             }
821 4030         23787 $token = undef; # force redo
822             }
823             elsif ($token eq 'ITEXT') {
824 740 100       1285 if ($inperl) {
825             # don't perform interpolation in PERL blocks
826 13         17 $token = 'TEXT';
827 13         40 $value = $text;
828             }
829             else {
830 727         6192 unshift(@$tokens,
831 727         930 @{ $self->interpolate_text($text, $line) });
832 727         4092 $token = undef; # force redo
833             }
834             }
835             }
836             else {
837             # toggle string flag to indicate if we're crossing
838             # a string boundary
839 24733 100       67568 $in_string = ! $in_string if $token eq '"';
840 24733         85481 $value = shift(@$tokens);
841             }
842             };
843             # clear undefined token to avoid 'undefined variable blah blah'
844             # warnings and let the parser logic pick it up in a minute
845 44028 100       126932 $token = '' unless defined $token;
846              
847             # get the next state for the current lookahead token
848 44028 100       138736 $action = defined ($lookup = $state->{'ACTIONS'}->{ $token })
    100          
849             ? $lookup
850             : defined ($lookup = $state->{'DEFAULT'})
851             ? $lookup
852             : undef;
853             }
854             else {
855             # no lookahead actions
856 48303         74574 $action = $state->{'DEFAULT'};
857             }
858              
859             # ERROR: no ACTION
860 92331 100       180266 last unless defined $action;
861              
862             # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
863             # shift (+ive ACTION)
864             # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
865 92328 100       202359 if ($action > 0) {
866 26022         66966 push(@$stack, [ $action, $value ]);
867 26022         39929 $token = $value = undef;
868 26022         33565 redo;
869             };
870              
871             # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
872             # reduce (-ive ACTION)
873             # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
874 66306         72465 ($lhs, $len, $code) = @{ $rules->[ -$action ] };
  66306         201260  
875              
876             # no action imples ACCEPTance
877 66306 100       191781 $action
878             or $status = ACCEPT;
879              
880             # use dummy sub if code ref doesn't exist
881 21458     21458   43016 $code = sub { $_[1] }
882 66306 100       175507 unless $code;
883              
884 91039         282269 @codevars = $len
885 66306 100       180919 ? map { $_->[1] } @$stack[ -$len .. -1 ]
886             : ();
887              
888 66306         105344 eval {
889 66306         189595 $coderet = &$code( $self, @codevars );
890             };
891 66306 50       265468 if ($@) {
892 0         0 my $err = $@;
893 0         0 chomp $err;
894 0         0 return $self->_parse_error($err);
895             }
896              
897             # reduce stack by $len
898 66306         111622 splice(@$stack, -$len, $len);
899              
900             # ACCEPT
901 66306 100       169640 return $coderet ## RETURN ##
902             if $status == ACCEPT;
903              
904             # ABORT
905             return undef ## RETURN ##
906 65028 50       124712 if $status == ABORT;
907              
908             # ERROR
909             last
910 65028 50       133233 if $status == ERROR;
911             }
912             continue {
913 65028         317399 push(@$stack, [ $states->[ $stack->[-1][0] ]->{'GOTOS'}->{ $lhs },
914             $coderet ]),
915             }
916              
917             # ERROR ## RETURN ##
918 3 100       19 return $self->_parse_error('unexpected end of input')
919             unless defined $value;
920              
921             # munge text of last directive to make it readable
922             # $text =~ s/\n/\\n/g;
923              
924 2 50       9 return $self->_parse_error("unexpected end of directive", $text)
925             if $value eq ';'; # end of directive SEPARATOR
926              
927 2         15 return $self->_parse_error("unexpected token ($value)", $text);
928             }
929              
930              
931              
932             #------------------------------------------------------------------------
933             # _parse_error($msg, $dirtext)
934             #
935             # Method used to handle errors encountered during the parse process
936             # in the _parse() method.
937             #------------------------------------------------------------------------
938              
939             sub _parse_error {
940 3     3   8 my ($self, $msg, $text) = @_;
941 3         9 my $line = $self->{ LINE };
942 3 50       15 $line = ref($line) ? $$line : $line;
943 3 50       13 $line = 'unknown' unless $line;
944              
945 3 100       16 $msg .= "\n [% $text %]"
946             if defined $text;
947              
948 3         47 return $self->error("line $line: $msg");
949             }
950              
951              
952             #------------------------------------------------------------------------
953             # _dump()
954             #
955             # Debug method returns a string representing the internal state of the
956             # object.
957             #------------------------------------------------------------------------
958              
959             sub _dump {
960 0     0     my $self = shift;
961 0           my $output = "[Template::Parser] {\n";
962 0           my $format = " %-16s => %s\n";
963 0           my $key;
964              
965 0           foreach $key (qw( START_TAG END_TAG TAG_STYLE ANYCASE INTERPOLATE
966             PRE_CHOMP POST_CHOMP V1DOLLAR )) {
967 0           my $val = $self->{ $key };
968 0 0         $val = '' unless defined $val;
969 0           $output .= sprintf($format, $key, $val);
970             }
971              
972 0           $output .= '}';
973 0           return $output;
974             }
975              
976              
977             1;
978              
979             __END__