File Coverage

lib/Template/Parser.pm
Criterion Covered Total %
statement 316 338 93.4
branch 152 182 83.5
condition 48 67 71.6
subroutine 30 31 96.7
pod 2 17 11.7
total 548 635 86.3


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   11289 use strict;
  80         169  
  80         3366  
36 80     80   458 use warnings;
  80         161  
  80         2895  
37 80     80   456 use base 'Template::Base';
  80         157  
  80         8374  
38              
39 80     80   518 use Template::Constants qw( :status :chomp );
  80         174  
  80         24410  
40 80     80   44301 use Template::Directive;
  80         274  
  80         2878  
41 80     80   97338 use Template::Grammar;
  80         105506  
  80         14723  
42              
43             # parser state constants
44 80     80   1043 use constant CONTINUE => 0;
  80         181  
  80         8331  
45 80     80   441 use constant ACCEPT => 1;
  80         181  
  80         3733  
46 80     80   481 use constant ERROR => 2;
  80         170  
  80         4724  
47 80     80   2200 use constant ABORT => 3;
  80         290  
  80         580424  
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 133     133 1 516 my $class = shift;
131 133 100 66     1633 my $config = $_[0] && ref($_[0]) eq 'HASH' ? shift(@_) : { @_ };
132 133         351 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 133   100     3154 FACTORY => $config->{ FACTORY } || 'Template::Directive',
151             }, $class;
152              
153             # update self with any relevant keys in config
154 133         1752 foreach $key (keys %$self) {
155 2128 100       4414 $self->{ $key } = $config->{ $key } if defined $config->{ $key };
156             }
157 133         618 $self->{ FILEINFO } = [ ];
158              
159             # DEBUG config item can be a bitmask
160 133 100       945 if (defined ($debug = $config->{ DEBUG })) {
    50          
161 15         51 $self->{ DEBUG } = $debug & ( Template::Constants::DEBUG_PARSER
162             | Template::Constants::DEBUG_FLAGS );
163 15         45 $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 118         450 $self->{ DEBUG } = $DEBUG & ( Template::Constants::DEBUG_PARSER
173             | Template::Constants::DEBUG_FLAGS );
174 118         399 $self->{ DEBUG_DIRS } = $DEBUG & Template::Constants::DEBUG_DIRS;
175             }
176              
177 133   33     911 $grammar = $self->{ GRAMMAR } ||= do {
178 133         1219 require Template::Grammar;
179 133         1226 Template::Grammar->new();
180             };
181              
182             # instantiate a FACTORY object
183 133 100       778 unless (ref $self->{ FACTORY }) {
184 132         413 my $fclass = $self->{ FACTORY };
185             $self->{ FACTORY } = $self->{ FACTORY }->new(
186             NAMESPACE => $config->{ NAMESPACE }
187             )
188 132   50     1909 || return $class->error($self->{ FACTORY }->error());
189             }
190              
191             # load grammar rules, states and lex table
192 133         1217 @$self{ qw( LEXTABLE STATES RULES ) }
193             = @$grammar{ qw( LEXTABLE STATES RULES ) };
194              
195 133 50       867 $self->new_style($config)
196             || return $class->error($self->error());
197              
198 133         1692 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 836 my ($self, $name) = @_;
210 130         331 my $blocks = $self->{ IN_BLOCK };
211 130         232 push(@{ $self->{ IN_BLOCK } }, $name);
  130         617  
212             }
213              
214             sub leave_block {
215 130     130 0 1020 my $self = shift;
216 130         485 my $label = $self->block_label;
217 130         214 pop(@{ $self->{ IN_BLOCK } });
  130         339  
218 130         798 return $label;
219             }
220              
221             sub in_block {
222 17     17 0 114 my ($self, $name) = @_;
223 17         42 my $blocks = $self->{ IN_BLOCK };
224 17   100     135 return @$blocks && $blocks->[-1] eq $name;
225             }
226              
227             sub block_label {
228 158     158 0 418 my ($self, $prefix, $suffix) = @_;
229 158         436 my $blocks = $self->{ IN_BLOCK };
230 158 100       636 my $name = @$blocks
231             ? $blocks->[-1] . scalar @$blocks
232             : undef;
233 158         323 return join('', grep { defined $_ } $prefix, $name, $suffix);
  474         1289  
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 134     134 0 319 my ($self, $config) = @_;
248 134   100     1146 my $styles = $self->{ STYLE } ||= [ ];
249 134         286 my ($tagstyle, $tags, $start, $end, $out, $key);
250              
251             # clone new style from previous or default style
252 134 100       258 my $style = { %{ $styles->[-1] || $DEFAULT_STYLE } };
  134         1570  
253              
254             # expand START_TAG and END_TAG from specified TAG_STYLE
255 134 100       807 if ($tagstyle = $config->{ TAG_STYLE }) {
256 3 50       14 return $self->error("Invalid tag style: $tagstyle")
257             unless defined ($tags = $TAG_STYLE->{ $tagstyle });
258 3         8 ($start, $end, $out) = @$tags;
259 3   33     27 $config->{ START_TAG } ||= $start;
260 3   33     15 $config->{ END_TAG } ||= $end;
261 3   33     13 $config->{ OUTLINE_TAG } ||= $out;
262             }
263              
264 134         546 foreach $key (keys %$DEFAULT_STYLE) {
265 1206 100       2606 $style->{ $key } = $config->{ $key } if defined $config->{ $key };
266             }
267              
268 134         430 $start = $style->{ START_TAG };
269 134         300 $end = $style->{ END_TAG };
270 134         288 $out = $style->{ OUTLINE_TAG };
271 134         622 $style->{ TEXT_SPLIT } = $self->text_splitter($start, $end, $out);
272              
273 134         442 push(@$styles, $style);
274 134         656 return $style;
275             }
276              
277             sub text_splitter {
278 149     149 0 406 my ($self, $start, $end, $out) = @_;
279              
280 149 50       720 if (defined $out) {
281 0         0 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 149         4141 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 5 my $self = shift;
319 1         3 my $styles = $self->{ STYLE };
320 1 50       4 return $self->error('only 1 parser style remaining')
321             unless (@$styles > 1);
322 1         1 pop @$styles;
323 1         3 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 1289     1289 1 2552 my ($self, $text, $info) = @_;
337 1289         1935 my ($tokens, $block);
338              
339             $info->{ DEBUG } = $self->{ DEBUG_DIRS }
340 1289 50       6550 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 1289         3432 my $defblock = $self->{ DEFBLOCK } = { };
346 1289         5788 my $metadata = $self->{ METADATA } = [ ];
347 1289         3434 my $variables = $self->{ VARIABLES } = { };
348 1289         3007 $self->{ DEFBLOCKS } = [ ];
349              
350 1289         3344 $self->{ _ERROR } = '';
351              
352             # split file into TEXT/DIRECTIVE chunks
353 1289   50     4873 $tokens = $self->split_text($text)
354             || return undef; ## RETURN ##
355              
356 1289         2395 push(@{ $self->{ FILEINFO } }, $info);
  1289         3721  
357              
358             # parse chunks
359 1289         5025 $block = $self->_parse($tokens, $info);
360              
361 1289         2367 pop(@{ $self->{ FILEINFO } });
  1289         3400  
362              
363 1289 100       3810 return undef unless $block; ## RETURN ##
364              
365             $self->debug("compiled main template document block:\n$block")
366 1286 50       4943 if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER;
367              
368             return {
369 1286         14832 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 1289     1289 0 2801 my ($self, $text) = @_;
386 1289         2000 my ($pre, $dir, $prelines, $dirlines, $postlines, $chomp, $tags, @tags);
387 1289         3838 my $style = $self->{ STYLE }->[-1];
388 1289         6314 my ($start, $end, $out, $prechomp, $postchomp, $interp ) =
389             @$style{ qw( START_TAG END_TAG OUTLINE_TAG PRE_CHOMP POST_CHOMP INTERPOLATE ) };
390 1289 100       9015 my $tags_dir = $self->{ANYCASE} ? qri : qr;
391 1289         2807 my $split = $style->{ TEXT_SPLIT };
392 1289         2852 my $has_out = defined $out;
393              
394 1289         2461 my @tokens = ();
395 1289         2152 my $line = 1;
396              
397             return \@tokens ## RETURN ##
398 1289 100 66     7541 unless defined $text && length $text;
399              
400             # extract all directives from the text
401 1282         16027 while ($text =~ s/$split//) {
402 3762         8597 $pre = $1;
403 3762 50       10908 $dir = defined($2) ? $2 : $3;
404 3762 50       8018 $pre = '' unless defined $pre;
405 3762 50       8011 $dir = '' unless defined $dir;
406              
407 3762         6659 $prelines = ($pre =~ tr/\n//); # newlines in preceding text
408 3762         6670 $dirlines = ($dir =~ tr/\n//); # newlines in directive tag
409 3762         5379 $postlines = 0; # newlines chomped after tag
410              
411 3762         11107 for ($dir) {
412 3762 100       9103 if (/^\#/) {
413             # comment out entire directive except for any end chomp flag
414 11 100       227 $dir = ($dir =~ /($CHOMP_FLAGS)$/o) ? $1 : '';
415             }
416             else {
417              
418 3751 100 33     28443 if(s/^($CHOMP_FLAGS)?(\s*)//so && $2) {
419 3741         6096 my $chomped = $2;
420 3741         5202 my $linecount = ($chomped =~ tr/\n//); # newlines in chomped whitespace
421 3741   100     14283 $linecount ||= 0;
422 3741         4720 $prelines += $linecount;
423 3741         6978 $dirlines -= $linecount;
424             }
425             # PRE_CHOMP: process whitespace before tag
426 3751 100       10030 $chomp = $1 ? $1 : $prechomp;
427 3751         5623 $chomp =~ tr/-=~+/1230/;
428 3751 100 100     10474 if ($chomp && $pre) {
429             # chomp off whitespace and newline preceding directive
430 118 100       359 if ($chomp == CHOMP_ALL) {
    100          
    50          
431 109         889 $pre =~ s{ (\r?\n|^) [^\S\n]* \z }{}mx;
432             }
433             elsif ($chomp == CHOMP_COLLAPSE) {
434 6         29 $pre =~ s{ (\s+) \z }{ }x;
435             }
436             elsif ($chomp == CHOMP_GREEDY) {
437 3         14 $pre =~ s{ (\s+) \z }{}x;
438             }
439             }
440             }
441              
442             # POST_CHOMP: process whitespace after tag
443 3762         40651 s/\s*($CHOMP_FLAGS)?\s*$//so;
444 3762 100       10953 $chomp = $1 ? $1 : $postchomp;
445 3762         5076 $chomp =~ tr/-=~+/1230/;
446 3762 100       10988 if ($chomp) {
447 1841 100       4861 if ($chomp == CHOMP_ALL) {
    100          
    50          
448 1832 100       12429 $text =~ s{ ^ ([^\S\n]* \n) }{}x
449             && $postlines++;
450             }
451             elsif ($chomp == CHOMP_COLLAPSE) {
452 6 50       43 $text =~ s{ ^ (\s+) }{ }x
453             && ($postlines += $1=~y/\n//);
454             }
455             # any trailing whitespace
456             elsif ($chomp == CHOMP_GREEDY) {
457 3 50       24 $text =~ s{ ^ (\s+) }{}x
458             && ($postlines += $1=~y/\n//);
459             }
460             }
461             }
462              
463             # any text preceding the directive can now be added
464 3762 100       9493 if (length $pre) {
465 2075 100       7077 push(@tokens, $interp
466             ? [ $pre, $line, 'ITEXT' ]
467             : ('TEXT', $pre) );
468             }
469 3762         4824 $line += $prelines;
470              
471             # and now the directive, along with line number information
472 3762 100       8232 if (length $dir) {
473             # the TAGS directive is a compile-time switch
474 3747 100       20055 if ($dir =~ /^$tags_dir\s+(.*)/) {
475 15         57 my @tags = split(/\s+/, $1);
476 15 100       62 if (scalar @tags > 1) {
    50          
477 7         13 ($start, $end, $out) = map { quotemeta($_) } @tags;
  14         43  
478 7         30 $split = $self->text_splitter($start, $end, $out);
479             }
480             elsif ($tags = $TAG_STYLE->{ $tags[0] }) {
481 8         23 ($start, $end, $out) = @$tags;
482 8         56 $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 3732 100       13941 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 3762         29251 $line += $dirlines + $postlines;
503             }
504              
505             # anything remaining in the string is plain text
506 1282 100       6063 push(@tokens, $interp
    100          
507             ? [ $text, $line, 'ITEXT' ]
508             : ( 'TEXT', $text) )
509             if length $text;
510              
511 1282         7730 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 901     901 0 2013 my ($self, $text, $line) = @_;
525 901         1450 my @tokens = ();
526 901         1244 my ($pre, $var, $dir);
527              
528              
529 901         6982 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 1401   66     6864 ($pre, $var, $dir) = ($1, $3 || $4, $2);
542              
543             # preceding text
544 1401 100 66     6082 if (defined($pre) && length($pre)) {
545 1092         2009 $line += $pre =~ tr/\n//;
546 1092         2094 $pre =~ s/\\\$/\$/g;
547 1092         2514 push(@tokens, 'TEXT', $pre);
548             }
549             # $variable reference
550 1401 100       5555 if ($var) {
    50          
551 309         563 $line += $dir =~ tr/\n/ /;
552 309         1031 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 901         4002 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 4041     4041 0 7881 my ($self, $text, $line) = @_;
591 4041         4914 my ($token, $uctoken, $type, $lookup);
592 4041         7346 my $lextable = $self->{ LEXTABLE };
593 4041         7577 my $style = $self->{ STYLE }->[-1];
594 4041         9836 my ($anycase, $start, $end) = @$style{ qw( ANYCASE START_TAG END_TAG ) };
595 4041         6187 my @tokens = ( );
596              
597 4041         35326 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 17066 100       37875 next if $1;
640              
641             # quoted string
642 17042 100       94114 if (defined ($token = $3)) {
    100          
    100          
    100          
    50          
643             # double-quoted string may include $variable references
644 1368 100       3492 if ($2 eq '"') {
645 316 100       1165 if ($token =~ /[\$\\]/) {
646 172         315 $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 172         393 for ($token) {
652 172         571 s/\\([^\$nrt])/$1/g;
653 172         686 s/\\([nrt])/$QUOTED_ESCAPES->{ $1 }/ge;
  109         601  
654             }
655 172         622 push(@tokens, ('"') x 2,
656 172         450 @{ $self->interpolate_text($token) },
657             ('"') x 2);
658 172         1310 next;
659             }
660             else {
661 144         273 $type = 'LITERAL';
662 144         553 $token =~ s['][\\']g;
663 144         506 $token = "'$token'";
664             }
665             }
666             else {
667 1052         1546 $type = 'LITERAL';
668 1052         2207 $token = "'$token'";
669             }
670             }
671             # number
672             elsif (defined ($token = $4)) {
673 717         1115 $type = 'NUMBER';
674             }
675             elsif (defined($token = $5)) {
676 26         44 $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 8715 100       15159 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 780 100 100     5817 if ((@tokens && $ANYCASE_AFTER->{ $tokens[-2] })
      100        
688             || ($text =~ /$ANYCASE_BEFORE/gc)) {
689             # keep the token unmodified
690 469         691 $uctoken = $token;
691             }
692             else {
693 311         580 $uctoken = uc $token;
694             }
695             }
696             else {
697 7935         11126 $uctoken = $token;
698             }
699 8715 100       30490 if (defined ($type = $lextable->{ $uctoken })) {
700 2231         5729 $token = $uctoken;
701             }
702             else {
703 6484         10028 $type = 'IDENT';
704             }
705             }
706             elsif (defined ($token = $7)) {
707             # reserved words may be in lower case unless case sensitive
708 6216 100       11547 $uctoken = $anycase ? uc $token : $token;
709 6216 50       19357 unless (defined ($type = $lextable->{ $uctoken })) {
710 0         0 $type = 'UNQUOTED';
711             }
712             }
713              
714 16870         129519 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 4041         21657 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 154     154 0 1893 my ($self, $name, $block) = @_;
741             my $defblock = $self->{ DEFBLOCK }
742 154   50     556 || return undef;
743              
744             $self->debug("compiled block '$name':\n$block")
745 154 50       552 if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER;
746              
747 154         462 $defblock->{ $name } = $block;
748              
749 154         365 return undef;
750             }
751              
752             sub push_defblock {
753 30     30 0 170 my $self = shift;
754 30   100     125 my $stack = $self->{ DEFBLOCK_STACK } ||= [];
755 30         82 push(@$stack, $self->{ DEFBLOCK } );
756 30         88 $self->{ DEFBLOCK } = { };
757             }
758              
759             sub pop_defblock {
760 30     30 0 189 my $self = shift;
761 30         73 my $defs = $self->{ DEFBLOCK };
762 30   50     102 my $stack = $self->{ DEFBLOCK_STACK } || return $defs;
763 30 50       83 return $defs unless @$stack;
764 30         65 $self->{ DEFBLOCK } = pop @$stack;
765 30         175 return $defs;
766             }
767              
768              
769             #------------------------------------------------------------------------
770             # add_metadata(\@setlist)
771             #------------------------------------------------------------------------
772              
773             sub add_metadata {
774 25     25 0 159 my ($self, $setlist) = @_;
775             my $metadata = $self->{ METADATA }
776 25   50     97 || return undef;
777              
778 25         66 push(@$metadata, @$setlist);
779              
780 25         69 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 3468     3468 0 18773 my $self = shift;
792 3468 100       9132 return "\n" unless $self->{ FILE_INFO };
793 3455         3850 my $line = ${ $self->{ LINE } };
  3455         7402  
794 3455         7435 my $info = $self->{ FILEINFO }->[-1];
795             my $file = $info->{ path } || $info->{ name }
796 3455   100     13736 || '(unknown template)';
797 3455         8530 $line =~ s/\-.*$//; # might be 'n-n'
798 3455   100     21811 $line ||= 1;
799 3455         19426 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 1289     1289   3270 my ($self, $tokens, $info) = @_;
824 1289         2371 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 1289         4342 my $stack = [ [ 0, undef ] ]; # DFA stack
828              
829             # DEBUG
830             # local $" = ', ';
831              
832             # retrieve internal rule and state tables
833 1289         6707 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 1289 50       4247 if $self->{ TRACE_VARS };
840              
841             # call the grammar set_factory method to install emitter factory
842 1289         7599 $self->{ GRAMMAR }->install_factory($self->{ FACTORY });
843              
844 1289         2311 $line = $inperl = 0;
845 1289         2925 $self->{ LINE } = \$line;
846 1289         3395 $self->{ FILE } = $info->{ name };
847 1289         2306 $self->{ INPERL } = \$inperl;
848              
849 1289         2235 $status = CONTINUE;
850 1289         1828 my $in_string = 0;
851              
852 1289         2050 while(1) {
853             # get state number and state
854 92623         136437 $stateno = $stack->[-1]->[0];
855 92623         124743 $state = $states->[$stateno];
856              
857             # see if any lookaheads exist for the current state
858 92623 100       207717 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 44169   100     170405 while (! defined $token && @$tokens) {
863 29574         48987 $token = shift(@$tokens);
864 29574 100       59944 if (ref $token) {
865 4781         12654 ($text, $line, $token) = @$token;
866 4781 100       14662 if (ref $token) {
    50          
867 4039 100 100     13216 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         21 my $dtext = $text;
875 15         26 $dtext =~ s[(['\\])][\\$1]g;
876 15         154 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 4024         26912 unshift(@$tokens, @$token, (';') x 2);
894             }
895 4039         24284 $token = undef; # force redo
896             }
897             elsif ($token eq 'ITEXT') {
898 742 100       1470 if ($inperl) {
899             # don't perform interpolation in PERL blocks
900 13         21 $token = 'TEXT';
901 13         37 $value = $text;
902             }
903             else {
904 729         2719 unshift(@$tokens,
905 729         914 @{ $self->interpolate_text($text, $line) });
906 729         4438 $token = undef; # force redo
907             }
908             }
909             }
910             else {
911             # toggle string flag to indicate if we're crossing
912             # a string boundary
913 24793 100       50558 $in_string = ! $in_string if $token eq '"';
914 24793         74111 $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 44169 100       81669 $token = '' unless defined $token;
920              
921             # get the next state for the current lookahead token
922 44169 100       135463 $action = defined ($lookup = $state->{'ACTIONS'}->{ $token })
    100          
923             ? $lookup
924             : defined ($lookup = $state->{'DEFAULT'})
925             ? $lookup
926             : undef;
927             }
928             else {
929             # no lookahead actions
930 48454         74734 $action = $state->{'DEFAULT'};
931             }
932              
933             # ERROR: no ACTION
934 92623 100       176546 last unless defined $action;
935              
936             # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
937             # shift (+ive ACTION)
938             # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
939 92620 100       173559 if ($action > 0) {
940 26090         69282 push(@$stack, [ $action, $value ]);
941 26090         36491 $token = $value = undef;
942 26090         33593 redo;
943             };
944              
945             # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
946             # reduce (-ive ACTION)
947             # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
948 66530         72644 ($lhs, $len, $code) = @{ $rules->[ -$action ] };
  66530         210648  
949              
950             # no action imples ACCEPTance
951 66530 100       170600 $action
952             or $status = ACCEPT;
953              
954             # use dummy sub if code ref doesn't exist
955 21555     21555   42813 $code = sub { $_[1] }
956 66530 100       161768 unless $code;
957              
958 91323         260807 @codevars = $len
959 66530 100       178165 ? map { $_->[1] } @$stack[ -$len .. -1 ]
960             : ();
961              
962 66530         106999 eval {
963 66530         170338 $coderet = &$code( $self, @codevars );
964             };
965 66530 50       238719 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 66530         123323 splice(@$stack, -$len, $len);
973              
974             # ACCEPT
975 66530 100       179408 return $coderet ## RETURN ##
976             if $status == ACCEPT;
977              
978             # ABORT
979             return undef ## RETURN ##
980 65244 50       121238 if $status == ABORT;
981              
982             # ERROR
983             last
984 65244 50       128307 if $status == ERROR;
985             }
986             continue {
987 65244         251620 push(@$stack, [ $states->[ $stack->[-1][0] ]->{'GOTOS'}->{ $lhs },
988             $coderet ]),
989             }
990              
991             # ERROR ## RETURN ##
992 3 100       21 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       9 return $self->_parse_error("unexpected end of directive", $text)
999             if $value eq ';'; # end of directive SEPARATOR
1000              
1001 2         16 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   10 my ($self, $msg, $text) = @_;
1015 3         8 my $line = $self->{ LINE };
1016 3 50       18 $line = ref($line) ? $$line : $line;
1017 3 50       13 $line = 'unknown' unless $line;
1018              
1019 3 100       18 $msg .= "\n [% $text %]"
1020             if defined $text;
1021              
1022 3         55 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__