[Templates-cvs] cvs commit: TT3/lib/Template Parser.pm
cvs@template-toolkit.org
cvs@template-toolkit.org
Fri, 03 Dec 2004 13:38:15 +0000
cvs 04/12/03 13:38:15
Modified: lib/Template Parser.pm
Log:
* added parse_tag() to handle nested tags
Revision Changes Path
1.19 +90 -21 TT3/lib/Template/Parser.pm
Index: Parser.pm
===================================================================
RCS file: /template-toolkit/TT3/lib/Template/Parser.pm,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- Parser.pm 2004/12/03 11:13:42 1.18
+++ Parser.pm 2004/12/03 13:38:15 1.19
@@ -18,7 +18,7 @@
# modify it under the same terms as Perl itself.
#
# REVISION
-# $Id: Parser.pm,v 1.18 2004/12/03 11:13:42 abw Exp $
+# $Id: Parser.pm,v 1.19 2004/12/03 13:38:15 abw Exp $
#
#========================================================================
@@ -29,7 +29,7 @@
use Template::Base;
use base qw( Template::Base );
-our $VERSION = sprintf("%d.%02d", q$Revision: 1.18 $ =~ /(\d+)\.(\d+)/);
+our $VERSION = sprintf("%d.%02d", q$Revision: 1.19 $ =~ /(\d+)\.(\d+)/);
our $DEBUG = 0 unless defined $DEBUG;
our $ERROR = '';
our $THROW = 'parser';
@@ -90,17 +90,19 @@
# regexen to match various unquoted strings. $IDENT matches a simple
# identifier (e.g. foo), while $KEYWORD adds the requirement of a word
-# boundary at the end (TODO: check why this is). $FILENAME allows
-# dots (e.g. foo.txt) and $RESOURCE allows dots and colon
-# (e.g. file:foo.txt). $HASHKEY matches valid hash keys which can be
+# boundary at the end (TODO: check why this is). $FILEPATH allows
+# dots, slashes and colon (e.g. /foo/bar.txt) and $RESOURCE is a
+# special case of this with an explicit leading resource identifier
+# (e.g. file:foo.txt). $HASHKEY matches valid hash keys which can be
# bare identifiers ($IDENT) or single quoted string ($SQUOTE). (TODO:
# why not double quoted strings?)
our $IDENT = qr/ \G ( \w+ ) /x;
our $KEYWORD = qr/ \G ( \w+ )\b /x;
-our $FILENAME = qr/ \G ( [\w\.\/:]+ ) /x;
+our $FILEPATH = qr/ \G ( [\w\.\/:]+ ) /x;
our $RESOURCE = qr/ \G ( \w+ ) : ( [\w\.\/:]+ ) /x;
our $HASHKEY = qr/ \G $IDENT | $SQUOTE /ox;
+our $PLUSPATH = qr/ \+ /x;
# regex to match the dot operator, making sure that another dot doesn't
# follow, preventing it from mistakenly identifying the list range op '..'
@@ -191,6 +193,7 @@
my $unary = $config->{ op_unary } || $self->pkgvar( UNARY => $UNARY );
my $binary = $config->{ op_binary } || $self->pkgvar( BINARY => $BINARY );
my $tertiary = $config->{ op_tertiary } || $self->pkgvar( TERTIARY => $TERTIARY );
+ my $pluspath = $config->{ op_pluspath } || $self->pkgvar( PLUSPATH => $PLUSPATH );
# construct regexen to match ignorable whitespace and comments,
# and various other punctuation tokens, including commas,
@@ -202,12 +205,15 @@
$self->{ wspace } = qr/ \G $wspace /x;
$self->{ comma } = qr/ \G (?:$wspace,)? $wspace /x;
$self->{ semicolon } = qr/ \G $wspace ; $wspace /x;
+ $self->{ pluspath } = qr/ \G $wspace $pluspath $wspace /x;
$self->{ assign } = qr/ \G $wspace ($assign) $wspace /x;
$self->{ range } = qr/ \G $wspace ($range) $wspace /x;
$self->{ unary } = qr/ \G $wspace ($unary) $wspace /x;
$self->{ binary } = qr/ \G $wspace ($binary) $wspace /x;
$self->{ tertiary } = qr/ \G $wspace ($tertiary->[0]) $wspace /x;
$self->{ otherwise } = qr/ \G $wspace ($tertiary->[1]) $wspace /x;
+ $self->{ tag_start } = qr/ \G $wspace ($config->{ tag_start }) /x
+ if $config->{ tag_start };
$self->{ tag_end } = qr/ (?= \G $wspace $tag_end ) /sx
if $tag_end;
@@ -367,7 +373,7 @@
sub parse_term {
my ($self, $textref) = @_;
- my ($term);
+ my ($term, $tag);
$self->debug("parse_term(", $self->next_chunk($textref), ")\n")
if $DEBUG;
@@ -375,8 +381,14 @@
# skip any leading whitespace
# $$textref =~ /$self->{ wspace }/cgx;
+
# match one of the term types
- if ($$textref =~ /$NUMBER/cog) {
+
+ if (($tag = $self->{ tag_start }) && ($$textref =~ /$tag/cg )) {
+ # the start of a nested tag
+ return $self->parse_tag($textref, $1);
+ }
+ elsif ($$textref =~ /$NUMBER/cog) {
$term = [ number => $1 ];
}
elsif ($$textref =~ /$SQUOTE/cog) {
@@ -435,6 +447,44 @@
+sub parse_tag {
+ my ($self, $textref, $start) = @_;
+
+ $self->debug("parse_tag(", $start, $self->next_chunk($textref), ")\n")
+ if $DEBUG;
+
+ # NOTE: temporary hack initiated by T::Tag::Directive scan()
+ my $match = $self->{ match }
+ || return $self->error("no match data to parse tag");
+ my $tag = $match->{ tag }
+ || return $self->error("no tag object");
+ my $handler = $match->{ handler }
+ || return $self->error("no tag handler");
+
+ # count any newlines consumed between last known offset (e.g. start
+ # of outer tag) and current position
+ my $off = $match->{ offset };
+ my $pos = pos $$textref;
+ my $sub = substr($$textref, $off, $pos - $off);
+ my $lines = ($sub =~ tr/\n//);
+
+ # create a new handler, detached from the current handler
+ $handler = $handler->new();
+
+ $match = {
+ text => $textref,
+ line => $match->{ line } + $lines,
+ start => $start,
+ offset => $pos,
+ };
+ $handler = $tag->scan($textref, $handler, $match)
+ || return $self->error($tag->error());
+
+ return $handler->end()
+ || $self->error($handler->error());
+}
+
+
#========================================================================
# terminals and other similar simple productions
#========================================================================
@@ -652,13 +702,13 @@
my $pos = pos $$textref;
- if ($$textref =~ /$FILENAME/cog) {
+ if ($$textref =~ /$FILEPATH/cog) {
# unquoted filename, but make sure it's not a directive keyword
if ($self->{ directives }->{ $1 }) {
pos $$textref = $pos;
return $self->decline("not a path (got keyword: $1)");
}
- $term = [ filename => $1 ];
+ $term = [ path => $1 ];
}
elsif ($$textref =~ /$SQUOTE/cog) {
$term = [ squote => $1 ];
@@ -697,6 +747,35 @@
#------------------------------------------------------------------------
+# parse_paths()
+#
+# Parse one or more template paths separated by '+'.
+#------------------------------------------------------------------------
+
+sub parse_paths {
+ my ($self, $textref) = @_;
+ my ($path, @paths);
+
+ $self->debug("parse_paths(", $self->next_chunk($textref), ")") if $DEBUG;
+
+ # skip any leading whitespace, comments, etc.
+ $$textref =~ /$self->{ wspace }/cg;
+
+ while ($path = $self->parse_path($textref)) {
+ push(@paths, $path);
+
+ # skip plus sign and/or whitespace
+ $$textref =~ /$self->{ pluspath }/cg;
+ }
+
+ # remove any trailing whitespace (TODO: is this required?)
+ $$textref =~ /$self->{ wspace }/cg;
+
+ return [ paths => \@paths ];
+}
+
+
+#------------------------------------------------------------------------
# parse_static_path($textref)
#
# Wrapper around parse_path() which sets the 'static' option to 1.
@@ -735,16 +814,6 @@
-#------------------------------------------------------------------------
-# parse_paths()
-#
-# Parse one or more template paths separated by '+'.
-#------------------------------------------------------------------------
-
-sub parse_paths {
- my $self = shift;
- return $self->error("parse_paths() not yet implemented");
-}
@@ -2576,7 +2645,7 @@
=head1 VERSION
-$Revision: 1.18 $
+$Revision: 1.19 $
=head1 COPYRIGHT