File Coverage

lib/Template/Parser.pm
Criterion Covered Total %
statement 317 338 93.7
branch 155 182 85.1
condition 49 67 73.1
subroutine 30 31 96.7
pod 2 17 11.7
total 553 635 87.0


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 85     85   6779 use strict;
  85         107  
  85         2229  
36 85     85   263 use warnings;
  85         88  
  85         2037  
37 85     85   302 use base 'Template::Base';
  85         88  
  85         5894  
38              
39 85     85   325 use Template::Constants qw( :status :chomp );
  85         99  
  85         14463  
40 85     85   26208 use Template::Directive;
  85         140  
  85         1943  
41 85     85   44739 use Template::Grammar;
  85         60167  
  85         8462  
42              
43             # parser state constants
44 85     85   565 use constant CONTINUE => 0;
  85         105  
  85         6102  
45 85     85   307 use constant ACCEPT => 1;
  85         105  
  85         3138  
46 85     85   280 use constant ERROR => 2;
  85         98  
  85         3561  
47 85     85   286 use constant ABORT => 3;
  85         155  
  85         287439  
48              
49             our $VERSION = 2.89;
50             our $DEBUG = 0 unless defined $DEBUG;
51             our $ERROR = '';
52              
53             # The ANYCASE option can cause conflicts when reserved words are used as
54             # variable names, hash keys, template names, plugin names, etc. The
55             #
56             # $ANYCASE_BEFORE regex identifies where such a word precedes an assignment,
57             # either as a variable (C) or hash key (C<{ wrapper => 'html' }).
58             # In that case it is treated as a simple words rather than being the lower case
59             # equivalent of the upper case keyword (e.g. WRAPPER).
60             #
61             # $ANYCASE_AFTER is used to identify when such a word follows a symbols that
62             # suggests it can't be a keyword, e.g. after BLOCK INCLUDE WRAPPER, USE, etc.
63             our $ANYCASE_BEFORE = qr/\G((?=\s*[=\.]))/;
64             our $ANYCASE_AFTER = {
65             map { $_ => 1 }
66             qw(
67             GET SET CALL DEFAULT INSERT INCLUDE PROCESS WRAPPER BLOCK USE
68             PLUGIN FILTER MACRO IN TO STEP AND OR NOT DIV MOD DOT
69             IF UNLESS ELSIF FOR WHILE SWITCH CASE META THROW CATCH VIEW
70             CMPOP BINOP COMMA
71             ),
72             '(', '[', '{'
73             # not sure about ASSIGN as it breaks C
74             };
75              
76              
77             #========================================================================
78             # -- COMMON TAG STYLES --
79             #========================================================================
80              
81             our $TAG_STYLE = {
82             'outline' => [ '\[%', '%\]', '%%' ], # NEW! Outline tag
83             'default' => [ '\[%', '%\]' ],
84             'template1' => [ '[\[%]%', '%[\]%]' ],
85             'metatext' => [ '%%', '%%' ],
86             'html' => [ '' ],
87             'mason' => [ '<%', '>' ],
88             'asp' => [ '<%', '%>' ],
89             'php' => [ '<\?', '\?>' ],
90             'star' => [ '\[\*', '\*\]' ],
91             };
92             $TAG_STYLE->{ template } = $TAG_STYLE->{ tt2 } = $TAG_STYLE->{ default };
93              
94              
95             our $DEFAULT_STYLE = {
96             START_TAG => $TAG_STYLE->{ default }->[0],
97             END_TAG => $TAG_STYLE->{ default }->[1],
98             OUTLINE_TAG => $TAG_STYLE->{ default }->[2],
99             # TAG_STYLE => 'default',
100             ANYCASE => 0,
101             INTERPOLATE => 0,
102             PRE_CHOMP => 0,
103             POST_CHOMP => 0,
104             V1DOLLAR => 0,
105             EVAL_PERL => 0,
106             };
107              
108             our $QUOTED_ESCAPES = {
109             n => "\n",
110             r => "\r",
111             t => "\t",
112             };
113              
114             # note that '-' must come first so Perl doesn't think it denotes a range
115             our $CHOMP_FLAGS = qr/[-=~+]/;
116              
117              
118              
119             #========================================================================
120             # ----- PUBLIC METHODS -----
121             #========================================================================
122              
123             #------------------------------------------------------------------------
124             # new(\%config)
125             #
126             # Constructor method.
127             #------------------------------------------------------------------------
128              
129             sub new {
130 143     143 1 284 my $class = shift;
131 143 100 100     1050 my $config = $_[0] && ref($_[0]) eq 'HASH' ? shift(@_) : { @_ };
132 143         206 my ($tagstyle, $debug, $start, $end, $defaults, $grammar, $hash, $key, $udef);
133              
134             my $self = bless {
135             START_TAG => undef,
136             END_TAG => undef,
137             OUTLINE_TAG => undef,
138             TAG_STYLE => 'default',
139             ANYCASE => 0,
140             INTERPOLATE => 0,
141             PRE_CHOMP => 0,
142             POST_CHOMP => 0,
143             V1DOLLAR => 0,
144             EVAL_PERL => 0,
145             FILE_INFO => 1,
146             GRAMMAR => undef,
147             _ERROR => '',
148             IN_BLOCK => [ ],
149             TRACE_VARS => $config->{ TRACE_VARS },
150 143   100     1839 FACTORY => $config->{ FACTORY } || 'Template::Directive',
151             }, $class;
152              
153             # update self with any relevant keys in config
154 143         1105 foreach $key (keys %$self) {
155 2288 100       2946 $self->{ $key } = $config->{ $key } if defined $config->{ $key };
156             }
157 143         337 $self->{ FILEINFO } = [ ];
158              
159             # DEBUG config item can be a bitmask
160 143 100       526 if (defined ($debug = $config->{ DEBUG })) {
    50          
161 15         30 $self->{ DEBUG } = $debug & ( Template::Constants::DEBUG_PARSER
162             | Template::Constants::DEBUG_FLAGS );
163 15         24 $self->{ DEBUG_DIRS } = $debug & Template::Constants::DEBUG_DIRS;
164             }
165             # package variable can be set to 1 to support previous behaviour
166             elsif ($DEBUG == 1) {
167 0         0 $self->{ DEBUG } = Template::Constants::DEBUG_PARSER;
168 0         0 $self->{ DEBUG_DIRS } = 0;
169             }
170             # otherwise let $DEBUG be a bitmask
171             else {
172 128         266 $self->{ DEBUG } = $DEBUG & ( Template::Constants::DEBUG_PARSER
173             | Template::Constants::DEBUG_FLAGS );
174 128         222 $self->{ DEBUG_DIRS } = $DEBUG & Template::Constants::DEBUG_DIRS;
175             }
176              
177 143   33     434 $grammar = $self->{ GRAMMAR } ||= do {
178 143         641 require Template::Grammar;
179 143         551 Template::Grammar->new();
180             };
181              
182             # instantiate a FACTORY object
183 143 100       406 unless (ref $self->{ FACTORY }) {
184 142         198 my $fclass = $self->{ FACTORY };
185             $self->{ FACTORY } = $self->{ FACTORY }->new(
186             NAMESPACE => $config->{ NAMESPACE }
187             )
188 142   50     1135 || return $class->error($self->{ FACTORY }->error());
189             }
190              
191             # load grammar rules, states and lex table
192             @$self{ qw( LEXTABLE STATES RULES ) }
193 143         629 = @$grammar{ qw( LEXTABLE STATES RULES ) };
194              
195 143 50       391 $self->new_style($config)
196             || return $class->error($self->error());
197              
198 143         1022 return $self;
199             }
200              
201             #-----------------------------------------------------------------------
202             # These methods are used to track nested IF and WHILE blocks. Each
203             # generated if/while block is given a label indicating the directive
204             # type and nesting depth, e.g. FOR0, WHILE1, FOR2, WHILE3, etc. The
205             # NEXT and LAST directives use the innermost label, e.g. last WHILE3;
206             #-----------------------------------------------------------------------
207              
208             sub enter_block {
209 130     130 0 372 my ($self, $name) = @_;
210 130         146 my $blocks = $self->{ IN_BLOCK };
211 130         102 push(@{ $self->{ IN_BLOCK } }, $name);
  130         285  
212             }
213              
214             sub leave_block {
215 130     130 0 475 my $self = shift;
216 130         225 my $label = $self->block_label;
217 130         116 pop(@{ $self->{ IN_BLOCK } });
  130         171  
218 130         341 return $label;
219             }
220              
221             sub in_block {
222 17     17 0 45 my ($self, $name) = @_;
223 17         19 my $blocks = $self->{ IN_BLOCK };
224 17   100     70 return @$blocks && $blocks->[-1] eq $name;
225             }
226              
227             sub block_label {
228 158     158 0 209 my ($self, $prefix, $suffix) = @_;
229 158         170 my $blocks = $self->{ IN_BLOCK };
230 158 100       364 my $name = @$blocks
231             ? $blocks->[-1] . scalar @$blocks
232             : undef;
233 158         180 return join('', grep { defined $_ } $prefix, $name, $suffix);
  474         707  
234             }
235              
236              
237              
238             #------------------------------------------------------------------------
239             # new_style(\%config)
240             #
241             # Install a new (stacked) parser style. This feature is currently
242             # experimental but should mimic the previous behaviour with regard to
243             # TAG_STYLE, START_TAG, END_TAG, etc.
244             #------------------------------------------------------------------------
245              
246             sub new_style {
247 144     144 0 180 my ($self, $config) = @_;
248 144   100     698 my $styles = $self->{ STYLE } ||= [ ];
249 144         194 my ($tagstyle, $tags, $start, $end, $out, $key);
250              
251             # clone new style from previous or default style
252 144 100       160 my $style = { %{ $styles->[-1] || $DEFAULT_STYLE } };
  144         1010  
253              
254             # expand START_TAG and END_TAG from specified TAG_STYLE
255 144 100       460 if ($tagstyle = $config->{ TAG_STYLE }) {
256             return $self->error("Invalid tag style: $tagstyle")
257 5 50       25 unless defined ($tags = $TAG_STYLE->{ $tagstyle });
258 5         12 ($start, $end, $out) = @$tags;
259 5   33     26 $config->{ START_TAG } ||= $start;
260 5   33     18 $config->{ END_TAG } ||= $end;
261 5   66     21 $config->{ OUTLINE_TAG } ||= $out;
262             }
263              
264 144         398 foreach $key (keys %$DEFAULT_STYLE) {
265 1296 100       1765 $style->{ $key } = $config->{ $key } if defined $config->{ $key };
266             }
267              
268 144         256 $start = $style->{ START_TAG };
269 144         197 $end = $style->{ END_TAG };
270 144         210 $out = $style->{ OUTLINE_TAG };
271 144         353 $style->{ TEXT_SPLIT } = $self->text_splitter($start, $end, $out);
272              
273 144         284 push(@$styles, $style);
274 144         390 return $style;
275             }
276              
277             sub text_splitter {
278 163     163 0 267 my ($self, $start, $end, $out) = @_;
279              
280 163 100       460 if (defined $out) {
281 6         147 return qr/
282             \A(.*?) # $1 - start of line up to directive
283             (?:
284             (?:
285             ^$out # outline tag at start of line
286             (.*?) # $2 - content of that line
287             (?:\n|$) # end of that line or file
288             )
289             |
290             (?:
291             $start # start of tag
292             (.*?) # $3 - tag contents
293             $end # end of tag
294             )
295             )
296             /msx;
297             }
298             else {
299 157         2422 return qr/
300             ^(.*?) # $1 - start of line up to directive
301             (?:
302             $start # start of tag
303             (.*?) # $2 - tag contents
304             $end # end of tag
305             )
306             /sx;
307             }
308             }
309              
310             #------------------------------------------------------------------------
311             # old_style()
312             #
313             # Pop the current parser style and revert to the previous one. See
314             # new_style(). ** experimental **
315             #------------------------------------------------------------------------
316              
317             sub old_style {
318 1     1 0 4 my $self = shift;
319 1         2 my $styles = $self->{ STYLE };
320 1 50       3 return $self->error('only 1 parser style remaining')
321             unless (@$styles > 1);
322 1         2 pop @$styles;
323 1         2 return $styles->[-1];
324             }
325              
326              
327             #------------------------------------------------------------------------
328             # parse($text, $data)
329             #
330             # Parses the text string, $text and returns a hash array representing
331             # the compiled template block(s) as Perl code, in the format expected
332             # by Template::Document.
333             #------------------------------------------------------------------------
334              
335             sub parse {
336 1310     1310 1 1331 my ($self, $text, $info) = @_;
337 1310         990 my ($tokens, $block);
338              
339             $info->{ DEBUG } = $self->{ DEBUG_DIRS }
340 1310 50       2998 unless defined $info->{ DEBUG };
341              
342             # print "info: { ", join(', ', map { "$_ => $info->{ $_ }" } keys %$info), " }\n";
343              
344             # store for blocks defined in the template (see define_block())
345 1310         1673 my $defblock = $self->{ DEFBLOCK } = { };
346 1310         3146 my $metadata = $self->{ METADATA } = [ ];
347 1310         1598 my $variables = $self->{ VARIABLES } = { };
348 1310         1403 $self->{ DEFBLOCKS } = [ ];
349              
350 1310         1467 $self->{ _ERROR } = '';
351              
352             # split file into TEXT/DIRECTIVE chunks
353 1310   50     2111 $tokens = $self->split_text($text)
354             || return undef; ## RETURN ##
355              
356 1310         1182 push(@{ $self->{ FILEINFO } }, $info);
  1310         1855  
357              
358             # parse chunks
359 1310         2235 $block = $self->_parse($tokens, $info);
360              
361 1310         1102 pop(@{ $self->{ FILEINFO } });
  1310         1653  
362              
363 1310 100       2105 return undef unless $block; ## RETURN ##
364              
365             $self->debug("compiled main template document block:\n$block")
366 1307 50       2455 if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER;
367              
368             return {
369 1307         6921 BLOCK => $block,
370             DEFBLOCKS => $defblock,
371             VARIABLES => $variables,
372             METADATA => { @$metadata },
373             };
374             }
375              
376              
377              
378             #------------------------------------------------------------------------
379             # split_text($text)
380             #
381             # Split input template text into directives and raw text chunks.
382             #------------------------------------------------------------------------
383              
384             sub split_text {
385 1311     1311 0 1261 my ($self, $text) = @_;
386 1311         1010 my ($pre, $dir, $prelines, $dirlines, $postlines, $chomp, $tags, @tags);
387 1311         1736 my $style = $self->{ STYLE }->[-1];
388             my ($start, $end, $out, $prechomp, $postchomp, $interp ) =
389 1311         2681 @$style{ qw( START_TAG END_TAG OUTLINE_TAG PRE_CHOMP POST_CHOMP INTERPOLATE ) };
390 1311 100       4235 my $tags_dir = $self->{ANYCASE} ? qri : qr;
391 1311         1285 my $split = $style->{ TEXT_SPLIT };
392 1311         1575 my $has_out = defined $out;
393              
394 1311         1391 my @tokens = ();
395 1311         1086 my $line = 1;
396              
397             return \@tokens ## RETURN ##
398 1311 100 66     4512 unless defined $text && length $text;
399              
400             # extract all directives from the text
401 1303         9050 while ($text =~ s/$split//) {
402 3833         5543 $pre = $1;
403 3833 100       6401 $dir = defined($2) ? $2 : $3;
404 3833 50       5189 $pre = '' unless defined $pre;
405 3833 50       4732 $dir = '' unless defined $dir;
406              
407 3833         3508 $prelines = ($pre =~ tr/\n//); # newlines in preceding text
408 3833         3256 $dirlines = ($dir =~ tr/\n//); # newlines in directive tag
409 3833         2988 $postlines = 0; # newlines chomped after tag
410              
411 3833         4221 for ($dir) {
412 3833 100       5010 if (/^\#/) {
413             # comment out entire directive except for any end chomp flag
414 11 100       187 $dir = ($dir =~ /($CHOMP_FLAGS)$/o) ? $1 : '';
415             }
416             else {
417              
418 3822 100 33     17898 if(s/^($CHOMP_FLAGS)?(\s*)//so && $2) {
419 3808         3537 my $chomped = $2;
420 3808         3017 my $linecount = ($chomped =~ tr/\n//); # newlines in chomped whitespace
421 3808   100     9100 $linecount ||= 0;
422 3808         2763 $prelines += $linecount;
423 3808         3408 $dirlines -= $linecount;
424             }
425             # PRE_CHOMP: process whitespace before tag
426 3822 100       5618 $chomp = $1 ? $1 : $prechomp;
427 3822         3142 $chomp =~ tr/-=~+/1230/;
428 3822 100 100     6459 if ($chomp && $pre) {
429             # chomp off whitespace and newline preceding directive
430 120 100       267 if ($chomp == CHOMP_ALL) {
    100          
    50          
431 111         497 $pre =~ s{ (\r?\n|^) [^\S\n]* \z }{}mx;
432             }
433             elsif ($chomp == CHOMP_COLLAPSE) {
434 6         20 $pre =~ s{ (\s+) \z }{ }x;
435             }
436             elsif ($chomp == CHOMP_GREEDY) {
437 3         11 $pre =~ s{ (\s+) \z }{}x;
438             }
439             }
440             }
441              
442             # POST_CHOMP: process whitespace after tag
443 3833         22657 s/\s*($CHOMP_FLAGS)?\s*$//so;
444 3833 100       5836 $chomp = $1 ? $1 : $postchomp;
445 3833         2990 $chomp =~ tr/-=~+/1230/;
446 3833 100       5654 if ($chomp) {
447 1856 100       3322 if ($chomp == CHOMP_ALL) {
    100          
    50          
448 1847 100       7019 $text =~ s{ ^ ([^\S\n]* \n) }{}x
449             && $postlines++;
450             }
451             elsif ($chomp == CHOMP_COLLAPSE) {
452 6 50       24 $text =~ s{ ^ (\s+) }{ }x
453             && ($postlines += $1=~y/\n//);
454             }
455             # any trailing whitespace
456             elsif ($chomp == CHOMP_GREEDY) {
457 3 50       14 $text =~ s{ ^ (\s+) }{}x
458             && ($postlines += $1=~y/\n//);
459             }
460             }
461             }
462              
463             # any text preceding the directive can now be added
464 3833 100       5111 if (length $pre) {
465 2119 100       4012 push(@tokens, $interp
466             ? [ $pre, $line, 'ITEXT' ]
467             : ('TEXT', $pre) );
468             }
469 3833         2796 $line += $prelines;
470              
471             # and now the directive, along with line number information
472 3833 100       4699 if (length $dir) {
473             # the TAGS directive is a compile-time switch
474 3818 100       10053 if ($dir =~ /^$tags_dir\s+(.*)/) {
475 19         53 my @tags = split(/\s+/, $1);
476 19 100       47 if (scalar @tags > 1) {
    50          
477 8         10 ($start, $end, $out) = map { quotemeta($_) } @tags;
  17         32  
478 8         19 $split = $self->text_splitter($start, $end, $out);
479             }
480             elsif ($tags = $TAG_STYLE->{ $tags[0] }) {
481 11         16 ($start, $end, $out) = @$tags;
482 11         17 $split = $self->text_splitter($start, $end, $out);
483             }
484             else {
485 0         0 warn "invalid TAGS style: $tags[0]\n";
486             }
487             }
488             else {
489             # DIRECTIVE is pushed as:
490             # [ $dirtext, $line_no(s), \@tokens ]
491 3799 100       7673 push(@tokens,
492             [ $dir,
493             ($dirlines
494             ? sprintf("%d-%d", $line, $line + $dirlines)
495             : $line),
496             $self->tokenise_directive($dir) ]);
497             }
498             }
499              
500             # update line counter to include directive lines and any extra
501             # newline chomped off the start of the following text
502 3833         16422 $line += $dirlines + $postlines;
503             }
504              
505             # anything remaining in the string is plain text
506 1303 100       3172 push(@tokens, $interp
    100          
507             ? [ $text, $line, 'ITEXT' ]
508             : ( 'TEXT', $text) )
509             if length $text;
510              
511 1303         4178 return \@tokens; ## RETURN ##
512             }
513              
514              
515              
516             #------------------------------------------------------------------------
517             # interpolate_text($text, $line)
518             #
519             # Examines $text looking for any variable references embedded like
520             # $this or like ${ this }.
521             #------------------------------------------------------------------------
522              
523             sub interpolate_text {
524 902     902 0 988 my ($self, $text, $line) = @_;
525 902         861 my @tokens = ();
526 902         681 my ($pre, $var, $dir);
527              
528              
529 902         4400 while ($text =~
530             /
531             ( (?: \\. | [^\$] ){1,3000} ) # escaped or non-'$' character [$1]
532             |
533             ( \$ (?: # embedded variable [$2]
534             (?: \{ ([^\}]*) \} ) # ${ ... } [$3]
535             |
536             ([\w\.]+) # $word [$4]
537             )
538             )
539             /gx) {
540              
541 1406   66     4214 ($pre, $var, $dir) = ($1, $3 || $4, $2);
542              
543             # preceding text
544 1406 100 66     3922 if (defined($pre) && length($pre)) {
545 1095         1109 $line += $pre =~ tr/\n//;
546 1095         1220 $pre =~ s/\\\$/\$/g;
547 1095         1428 push(@tokens, 'TEXT', $pre);
548             }
549             # $variable reference
550 1406 100       3585 if ($var) {
    50          
551 311         371 $line += $dir =~ tr/\n/ /;
552 311         676 push(@tokens, [ $dir, $line, $self->tokenise_directive($var) ]);
553             }
554             # other '$' reference - treated as text
555             elsif ($dir) {
556 0         0 $line += $dir =~ tr/\n//;
557 0         0 push(@tokens, 'TEXT', $dir);
558             }
559             }
560              
561 902         2278 return \@tokens;
562             }
563              
564              
565              
566             #------------------------------------------------------------------------
567             # tokenise_directive($text)
568             #
569             # Called by the private _parse() method when it encounters a DIRECTIVE
570             # token in the list provided by the split_text() or interpolate_text()
571             # methods. The directive text is passed by parameter.
572             #
573             # The method splits the directive into individual tokens as recognised
574             # by the parser grammar (see Template::Grammar for details). It
575             # constructs a list of tokens each represented by 2 elements, as per
576             # split_text() et al. The first element contains the token type, the
577             # second the token itself.
578             #
579             # The method tokenises the string using a complex (but fast) regex.
580             # For a deeper understanding of the regex magic at work here, see
581             # Jeffrey Friedl's excellent book "Mastering Regular Expressions",
582             # from O'Reilly, ISBN 1-56592-257-3
583             #
584             # Returns a reference to the list of chunks (each one being 2 elements)
585             # identified in the directive text. On error, the internal _ERROR string
586             # is set and undef is returned.
587             #------------------------------------------------------------------------
588              
589             sub tokenise_directive {
590 4110     4110 0 4357 my ($self, $text, $line) = @_;
591 4110         2732 my ($token, $uctoken, $type, $lookup);
592 4110         3606 my $lextable = $self->{ LEXTABLE };
593 4110         3455 my $style = $self->{ STYLE }->[-1];
594 4110         5126 my ($anycase, $start, $end) = @$style{ qw( ANYCASE START_TAG END_TAG ) };
595 4110         3552 my @tokens = ( );
596              
597 4110         18213 while ($text =~
598             /
599             # strip out any comments
600             (\#[^\n]*)
601             |
602             # a quoted phrase matches in $3
603             (["']) # $2 - opening quote, ' or "
604             ( # $3 - quoted text buffer
605             (?: # repeat group (no backreference)
606             \\\\ # an escaped backslash \\
607             | # ...or...
608             \\\2 # an escaped quote \" or \' (match $1)
609             | # ...or...
610             . # any other character
611             | \n
612             )*? # non-greedy repeat
613             ) # end of $3
614             \2 # match opening quote
615             |
616             # an unquoted number matches in $4
617             (-?\d+(?:\.\d+)?) # numbers
618             |
619             # filename matches in $5
620             ( \/?\w+(?:(?:\/|::?)\w*)+ | \/\w+)
621             |
622             # an identifier matches in $6
623             (\w+) # variable identifier
624             |
625             # an unquoted word or symbol matches in $7
626             ( [(){}\[\]:;,\/\\] # misc parenthesis and symbols
627             # | \-> # arrow operator (for future?)
628             | [+\-*] # math operations
629             | \$\{? # dollar with option left brace
630             | => # like '='
631             | [=!<>]?= | [!<>] # eqality tests
632             | &&? | \|\|? # boolean ops
633             | \.\.? # n..n sequence
634             | \S+ # something unquoted
635             ) # end of $7
636             /gmxo) {
637              
638             # ignore comments to EOL
639 17302 100       23549 next if $1;
640              
641             # quoted string
642 17277 100       45783 if (defined ($token = $3)) {
    100          
    100          
    100          
    50          
643             # double-quoted string may include $variable references
644 1385 100       2080 if ($2 eq '"') {
645 323 100       681 if ($token =~ /[\$\\]/) {
646 173         204 $type = 'QUOTED';
647             # unescape " and \ but leave \$ escaped so that
648             # interpolate_text() doesn't incorrectly treat it
649             # as a variable reference
650             # $token =~ s/\\([\\"])/$1/g;
651 173         252 for ($token) {
652 173         326 s/\\([^\$nrt])/$1/g;
653 173         372 s/\\([nrt])/$QUOTED_ESCAPES->{ $1 }/ge;
  110         310  
654             }
655             push(@tokens, ('"') x 2,
656 173         274 @{ $self->interpolate_text($token) },
  173         333  
657             ('"') x 2);
658 173         753 next;
659             }
660             else {
661 150         158 $type = 'LITERAL';
662 150         186 $token =~ s['][\\']g;
663 150         222 $token = "'$token'";
664             }
665             }
666             else {
667 1062         824 $type = 'LITERAL';
668 1062         1241 $token = "'$token'";
669             }
670             }
671             # number
672             elsif (defined ($token = $4)) {
673 721         609 $type = 'NUMBER';
674             }
675             elsif (defined($token = $5)) {
676 26         24 $type = 'FILENAME';
677             }
678             elsif (defined($token = $6)) {
679             # Fold potential keywords to UPPER CASE if the ANYCASE option is
680             # set, unless (we've got some preceding tokens and) the previous
681             # token is a DOT op. This prevents the 'last' in 'data.last'
682             # from being interpreted as the LAST keyword.
683 8846 100       8793 if ($anycase) {
684             # if the token follows a dot or precedes an assignment then
685             # it's not for folding, e.g. the 'wrapper' in this:
686             # [% page = { wrapper='html' }; page.wrapper %]
687 817 100 100     4037 if ((@tokens && $ANYCASE_AFTER->{ $tokens[-2] })
      100        
688             || ($text =~ /$ANYCASE_BEFORE/gc)) {
689             # keep the token unmodified
690 491         377 $uctoken = $token;
691             }
692             else {
693 326         348 $uctoken = uc $token;
694             }
695             }
696             else {
697 8029         5853 $uctoken = $token;
698             }
699 8846 100       11615 if (defined ($type = $lextable->{ $uctoken })) {
700 2274         2971 $token = $uctoken;
701             }
702             else {
703 6572         5278 $type = 'IDENT';
704             }
705             }
706             elsif (defined ($token = $7)) {
707             # reserved words may be in lower case unless case sensitive
708 6299 100       6531 $uctoken = $anycase ? uc $token : $token;
709 6299 50       9363 unless (defined ($type = $lextable->{ $uctoken })) {
710 0         0 $type = 'UNQUOTED';
711             }
712             }
713              
714 17104         63556 push(@tokens, $type, $token);
715              
716             # print(STDERR " +[ $type, $token ]\n")
717             # if $DEBUG;
718             }
719              
720             # print STDERR "tokenise directive() returning:\n [ @tokens ]\n"
721             # if $DEBUG;
722              
723 4110         11473 return \@tokens; ## RETURN ##
724             }
725              
726              
727             #------------------------------------------------------------------------
728             # define_block($name, $block)
729             #
730             # Called by the parser 'defblock' rule when a BLOCK definition is
731             # encountered in the template. The name of the block is passed in the
732             # first parameter and a reference to the compiled block is passed in
733             # the second. This method stores the block in the $self->{ DEFBLOCK }
734             # hash which has been initialised by parse() and will later be used
735             # by the same method to call the store() method on the calling cache
736             # to define the block "externally".
737             #------------------------------------------------------------------------
738              
739             sub define_block {
740 157     157 0 1022 my ($self, $name, $block) = @_;
741             my $defblock = $self->{ DEFBLOCK }
742 157   50     345 || return undef;
743              
744             $self->debug("compiled block '$name':\n$block")
745 157 50       307 if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER;
746              
747 157         275 $defblock->{ $name } = $block;
748              
749 157         200 return undef;
750             }
751              
752             sub push_defblock {
753 30     30 0 82 my $self = shift;
754 30   100     91 my $stack = $self->{ DEFBLOCK_STACK } ||= [];
755 30         56 push(@$stack, $self->{ DEFBLOCK } );
756 30         61 $self->{ DEFBLOCK } = { };
757             }
758              
759             sub pop_defblock {
760 30     30 0 94 my $self = shift;
761 30         34 my $defs = $self->{ DEFBLOCK };
762 30   50     59 my $stack = $self->{ DEFBLOCK_STACK } || return $defs;
763 30 50       43 return $defs unless @$stack;
764 30         38 $self->{ DEFBLOCK } = pop @$stack;
765 30         75 return $defs;
766             }
767              
768              
769             #------------------------------------------------------------------------
770             # add_metadata(\@setlist)
771             #------------------------------------------------------------------------
772              
773             sub add_metadata {
774 25     25 0 102 my ($self, $setlist) = @_;
775             my $metadata = $self->{ METADATA }
776 25   50     74 || return undef;
777              
778 25         45 push(@$metadata, @$setlist);
779              
780 25         38 return undef;
781             }
782              
783              
784             #------------------------------------------------------------------------
785             # location()
786             #
787             # Return Perl comment indicating current parser file and line
788             #------------------------------------------------------------------------
789              
790             sub location {
791 3528     3528 0 9875 my $self = shift;
792 3528 100       5320 return "\n" unless $self->{ FILE_INFO };
793 3515         2342 my $line = ${ $self->{ LINE } };
  3515         3935  
794 3515         3333 my $info = $self->{ FILEINFO }->[-1];
795             my $file = $info->{ path } || $info->{ name }
796 3515   50     5446 || '(unknown template)';
797 3515         5562 $line =~ s/\-.*$//; # might be 'n-n'
798 3515   100     4838 $line ||= 1;
799 3515         9279 return "#line $line \"$file\"\n";
800             }
801              
802              
803             #========================================================================
804             # ----- PRIVATE METHODS -----
805             #========================================================================
806              
807             #------------------------------------------------------------------------
808             # _parse(\@tokens, \@info)
809             #
810             # Parses the list of input tokens passed by reference and returns a
811             # Template::Directive::Block object which contains the compiled
812             # representation of the template.
813             #
814             # This is the main parser DFA loop. See embedded comments for
815             # further details.
816             #
817             # On error, undef is returned and the internal _ERROR field is set to
818             # indicate the error. This can be retrieved by calling the error()
819             # method.
820             #------------------------------------------------------------------------
821              
822             sub _parse {
823 1310     1310   1310 my ($self, $tokens, $info) = @_;
824 1310         1014 my ($token, $value, $text, $line, $inperl);
825 0         0 my ($state, $stateno, $status, $action, $lookup, $coderet, @codevars);
826 0         0 my ($lhs, $len, $code); # rule contents
827 1310         1906 my $stack = [ [ 0, undef ] ]; # DFA stack
828              
829             # DEBUG
830             # local $" = ', ';
831              
832             # retrieve internal rule and state tables
833 1310         1909 my ($states, $rules) = @$self{ qw( STATES RULES ) };
834              
835             # If we're tracing variable usage then we need to give the factory a
836             # reference to our $self->{ VARIABLES } for it to fill in. This is a
837             # bit of a hack to back-patch this functionality into TT2.
838             $self->{ FACTORY }->trace_vars($self->{ VARIABLES })
839 1310 100       2222 if $self->{ TRACE_VARS };
840              
841             # call the grammar set_factory method to install emitter factory
842 1310         3274 $self->{ GRAMMAR }->install_factory($self->{ FACTORY });
843              
844 1310         1057 $line = $inperl = 0;
845 1310         1412 $self->{ LINE } = \$line;
846 1310         1623 $self->{ FILE } = $info->{ name };
847 1310         1178 $self->{ INPERL } = \$inperl;
848              
849 1310         1055 $status = CONTINUE;
850 1310         1047 my $in_string = 0;
851              
852 1310         980 while(1) {
853             # get state number and state
854 94008         64446 $stateno = $stack->[-1]->[0];
855 94008         60266 $state = $states->[$stateno];
856              
857             # see if any lookaheads exist for the current state
858 94008 100       95061 if (exists $state->{'ACTIONS'}) {
859              
860             # get next token and expand any directives (i.e. token is an
861             # array ref) onto the front of the token list
862 44826   100     99594 while (! defined $token && @$tokens) {
863 30006         24404 $token = shift(@$tokens);
864 30006 100       30732 if (ref $token) {
865 4849         6093 ($text, $line, $token) = @$token;
866 4849 100       7030 if (ref $token) {
    50          
867 4107 100 100     7727 if ($info->{ DEBUG } && ! $in_string) {
868             # - - - - - - - - - - - - - - - - - - - - - - - - -
869             # This is gnarly. Look away now if you're easily
870             # frightened. We're pushing parse tokens onto the
871             # pending list to simulate a DEBUG directive like so:
872             # [% DEBUG msg line='20' text='INCLUDE foo' %]
873             # - - - - - - - - - - - - - - - - - - - - - - - - -
874 15         18 my $dtext = $text;
875 15         19 $dtext =~ s[(['\\])][\\$1]g;
876 15         105 unshift(@$tokens,
877             DEBUG => 'DEBUG',
878             IDENT => 'msg',
879             IDENT => 'line',
880             ASSIGN => '=',
881             LITERAL => "'$line'",
882             IDENT => 'text',
883             ASSIGN => '=',
884             LITERAL => "'$dtext'",
885             IDENT => 'file',
886             ASSIGN => '=',
887             LITERAL => "'$info->{ name }'",
888             (';') x 2,
889             @$token,
890             (';') x 2);
891             }
892             else {
893 4092         13581 unshift(@$tokens, @$token, (';') x 2);
894             }
895 4107         13417 $token = undef; # force redo
896             }
897             elsif ($token eq 'ITEXT') {
898 742 100       821 if ($inperl) {
899             # don't perform interpolation in PERL blocks
900 13         14 $token = 'TEXT';
901 13         25 $value = $text;
902             }
903             else {
904             unshift(@$tokens,
905 729         535 @{ $self->interpolate_text($text, $line) });
  729         1078  
906 729         2369 $token = undef; # force redo
907             }
908             }
909             }
910             else {
911             # toggle string flag to indicate if we're crossing
912             # a string boundary
913 25157 100       31040 $in_string = ! $in_string if $token eq '"';
914 25157         40345 $value = shift(@$tokens);
915             }
916             };
917             # clear undefined token to avoid 'undefined variable blah blah'
918             # warnings and let the parser logic pick it up in a minute
919 44826 100       51960 $token = '' unless defined $token;
920              
921             # get the next state for the current lookahead token
922             $action = defined ($lookup = $state->{'ACTIONS'}->{ $token })
923             ? $lookup
924 44826 100       61441 : defined ($lookup = $state->{'DEFAULT'})
    100          
925             ? $lookup
926             : undef;
927             }
928             else {
929             # no lookahead actions
930 49182         32960 $action = $state->{'DEFAULT'};
931             }
932              
933             # ERROR: no ACTION
934 94008 100       102305 last unless defined $action;
935              
936             # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
937             # shift (+ive ACTION)
938             # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
939 94005 100       102521 if ($action > 0) {
940 26475         29782 push(@$stack, [ $action, $value ]);
941 26475         20058 $token = $value = undef;
942 26475         18304 redo;
943             };
944              
945             # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
946             # reduce (-ive ACTION)
947             # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
948 67530         38233 ($lhs, $len, $code) = @{ $rules->[ -$action ] };
  67530         71487  
949              
950             # no action imples ACCEPTance
951 67530 100       88298 $action
952             or $status = ACCEPT;
953              
954             # use dummy sub if code ref doesn't exist
955 21870     21870   20066 $code = sub { $_[1] }
956 67530 100       95618 unless $code;
957              
958             @codevars = $len
959 67530 100       92409 ? map { $_->[1] } @$stack[ -$len .. -1 ]
  92687         125941  
960             : ();
961              
962 67530         51996 eval {
963 67530         81354 $coderet = &$code( $self, @codevars );
964             };
965 67530 50       132487 if ($@) {
966 0         0 my $err = $@;
967 0         0 chomp $err;
968 0         0 return $self->_parse_error($err);
969             }
970              
971             # reduce stack by $len
972 67530         57013 splice(@$stack, -$len, $len);
973              
974             # ACCEPT
975 67530 100       87777 return $coderet ## RETURN ##
976             if $status == ACCEPT;
977              
978             # ABORT
979             return undef ## RETURN ##
980 66223 50       69749 if $status == ABORT;
981              
982             # ERROR
983             last
984 66223 50       72805 if $status == ERROR;
985             }
986             continue {
987 66223         100141 push(@$stack, [ $states->[ $stack->[-1][0] ]->{'GOTOS'}->{ $lhs },
988             $coderet ]),
989             }
990              
991             # ERROR ## RETURN ##
992 3 100       14 return $self->_parse_error('unexpected end of input')
993             unless defined $value;
994              
995             # munge text of last directive to make it readable
996             # $text =~ s/\n/\\n/g;
997              
998 2 50       7 return $self->_parse_error("unexpected end of directive", $text)
999             if $value eq ';'; # end of directive SEPARATOR
1000              
1001 2         10 return $self->_parse_error("unexpected token ($value)", $text);
1002             }
1003              
1004              
1005              
1006             #------------------------------------------------------------------------
1007             # _parse_error($msg, $dirtext)
1008             #
1009             # Method used to handle errors encountered during the parse process
1010             # in the _parse() method.
1011             #------------------------------------------------------------------------
1012              
1013             sub _parse_error {
1014 3     3   6 my ($self, $msg, $text) = @_;
1015 3         5 my $line = $self->{ LINE };
1016 3 50       10 $line = ref($line) ? $$line : $line;
1017 3 50       9 $line = 'unknown' unless $line;
1018              
1019 3 100       12 $msg .= "\n [% $text %]"
1020             if defined $text;
1021              
1022 3         38 return $self->error("line $line: $msg");
1023             }
1024              
1025              
1026             #------------------------------------------------------------------------
1027             # _dump()
1028             #
1029             # Debug method returns a string representing the internal state of the
1030             # object.
1031             #------------------------------------------------------------------------
1032              
1033             sub _dump {
1034 0     0     my $self = shift;
1035 0           my $output = "[Template::Parser] {\n";
1036 0           my $format = " %-16s => %s\n";
1037 0           my $key;
1038              
1039 0           foreach $key (qw( START_TAG END_TAG TAG_STYLE ANYCASE INTERPOLATE
1040             PRE_CHOMP POST_CHOMP V1DOLLAR )) {
1041 0           my $val = $self->{ $key };
1042 0 0         $val = '' unless defined $val;
1043 0           $output .= sprintf($format, $key, $val);
1044             }
1045              
1046 0           $output .= '}';
1047 0           return $output;
1048             }
1049              
1050              
1051             1;
1052              
1053             __END__