[Templates-cvs] cvs commit: TT3/lib/Template Parser.pm
cvs@template-toolkit.org
cvs@template-toolkit.org
Fri, 03 Dec 2004 11:13:43 +0000
cvs 04/12/03 11:13:43
Modified: lib/Template Parser.pm
Log:
* extracted all error messages out into $ERROR package hash
* added parse_path() and parse_static_path() methods
* deprecated some old methods
Revision Changes Path
1.18 +398 -255 TT3/lib/Template/Parser.pm
Index: Parser.pm
===================================================================
RCS file: /template-toolkit/TT3/lib/Template/Parser.pm,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- Parser.pm 2004/12/02 16:46:34 1.17
+++ Parser.pm 2004/12/03 11:13:42 1.18
@@ -18,7 +18,7 @@
# modify it under the same terms as Perl itself.
#
# REVISION
-# $Id: Parser.pm,v 1.17 2004/12/02 16:46:34 abw Exp $
+# $Id: Parser.pm,v 1.18 2004/12/03 11:13:42 abw Exp $
#
#========================================================================
@@ -29,7 +29,7 @@
use Template::Base;
use base qw( Template::Base );
-our $VERSION = sprintf("%d.%02d", q$Revision: 1.17 $ =~ /(\d+)\.(\d+)/);
+our $VERSION = sprintf("%d.%02d", q$Revision: 1.18 $ =~ /(\d+)\.(\d+)/);
our $DEBUG = 0 unless defined $DEBUG;
our $ERROR = '';
our $THROW = 'parser';
@@ -119,6 +119,38 @@
our $ENDPAREN = qr/ \G \) /x;
+#------------------------------------------------------------------------
+# error messages throw by the parser
+#------------------------------------------------------------------------
+
+our $ERRORS = {
+ unterminated_string => 'unterminated string (missing %s)',
+ text_after_embedded => 'unexpected text after embedded variable: %s',
+ end_tag_after_binop => "unexpected end of directive tag after '%s'",
+ no_static_variables => 'variables are not allowed in static paths',
+ no_right_bracket => 'no right bracket defined to match $1',
+ internal_error => 'internal error in %s, please notify the developers',
+ bad_expr_after => "unexpected %s after '%s' where expression expected",
+ args_end_text => 'unexpected end of text in argument list',
+ in_list_def => 'unexpected %s in list definition [ ... ]',
+ in_hash_def => 'unexpected %s in hash definition { ... }',
+ in_parens => 'unexpected %s in parentheses ( ... )',
+ in_args => 'unexpected %s in argument list ( ... )',
+ no_colon => "missing ':' after tertiary '%s' expression (%s)",
+ no_dot_item => "missing item after '.' (%s)",
+ no_variable => "missing variable after \$ (%s)",
+ no_embedded => "missing variable in \${ ... } (%s)",
+ no_end_paren => "missing ')' at end of argument list (%s)",
+ missing_after => "missing '%s' after '%s' (%s)",
+ no_key_assign => "missing assignment after key %s (%s)",
+ no_var_assign => "missing assignment after variable (%s)",
+ no_expr_after => "missing expression after '%s' (%s)",
+ no_hash_assign => "missing assignment after hash key %s (%s)",
+ no_param_assign => "missing assignment after parameter %s (%s)",
+ no_ident_assign => "missing assignment after identifier '%s' (%s)",
+};
+
+
#------------------------------------------------------------------------
# init()
@@ -218,7 +250,7 @@
# check for end of tag
if ($tag_end && ($$textref =~ /$tag_end/cg)) {
- return $self->error("unexpected end of directive tag after '$binop'")
+ return $self->error_msg( end_tag_after_binop => $binop )
if @terms;
$stop = 1;
last CHUNK;
@@ -235,8 +267,7 @@
$term = [ unary => $unop, $term ];
}
else {
- return $self->unexpected($textref,
- "after '$unop' where expression expected");
+ return $self->unexpected($textref, bad_expr_after => $unop);
}
}
elsif ($term = $self->parse_term($textref)) {
@@ -247,8 +278,7 @@
# we haven't found a term, but we've already got some
# terms push onto @terms, so this must be coming after
# a binary operator, which means it's a syntax error
- return $self->unexpected($textref,
- "after '$binop' where expression expected");
+ return $self->unexpected($textref, bad_expr_after => $binop);
}
else {
$self->debug("no term\n") if $DEBUG;
@@ -299,20 +329,18 @@
$self->debug("expr tertiary operator: $op\n") if $DEBUG;
$true = $self->parse_expression($textref)
- || return $self->unexpected($textref,
- "after '$op' where expression expected");
+ || return $self->unexpected($textref, bad_expr_after => $op);
# NOTE: tertiary operator could be redefined to something other
# than ':' so this error message could be wrong, but we can't
# print out the value we're looking for because it's a regex
- return $self->missing($textref, "':' after expression following '$op'")
+ return $self->missing($textref, no_colon => $op)
unless $$textref =~ /$self->{ otherwise }/cg;
$op = $1;
$false = $self->parse_expression($textref)
- || return $self->unexpected($textref,
- "after '$op' where expression expected");
+ || return $self->unexpected($textref, bad_expr_after => $op);
$expr = [ tertiary => $expr, $true, $false ];
}
@@ -361,7 +389,7 @@
}
elsif ($$textref =~ /$BADQUOTE/cog) {
# check for unterminated strings - a common error
- return $self->error("unterminated string (missing $1)");
+ return $self->error_msg( unterminated_string => $1 );
}
elsif ($$textref =~ /$QWLIST/cog) {
$term = $self->parse_qwlist($textref, $1) || return;
@@ -369,17 +397,17 @@
}
elsif ($$textref =~ /$LIST/cog) {
$term = $self->parse_list($textref) || return;
- return $self->unexpected($textref, 'in list definition [ ... ]')
+ return $self->unexpected($textref, 'in_list_def')
unless $$textref =~ /$ENDLIST/cog;
}
elsif ($$textref =~ /$HASH/cog) {
$term = $self->parse_hash($textref) || return;
- return $self->unexpected($textref, 'in hash definition { ... }')
+ return $self->unexpected($textref, 'in_hash_def')
unless $$textref =~ /$ENDHASH/cog;
}
elsif ($$textref =~ /$PAREN/cog) {
$term = $self->parse_parens($textref) || return;
- return $self->unexpected($textref, 'in parentheses ( ... )')
+ return $self->unexpected($textref, 'in_parens')
unless $$textref =~ /$ENDPAREN/cog;
$term = [ parens => $term ];
}
@@ -536,11 +564,11 @@
# embedded ${ variable }
my $text = $2;
$token = $self->parse_variable(\$text)
- || return $self->missing($textref, "variable in '\${ }'");
+ || return $self->missing($textref, 'no_embedded');
if ($text =~ / \G \s* (.+) /cgsx) {
$text = $1;
$text =~ s/\n/\\n/g;
- return $self->error("unexpected text after embedded variable: $text");
+ return $self->error_msg( text_after_embedded => $text );
}
push(@tokens, $token);
}
@@ -548,11 +576,12 @@
# $variable reference
my $text = $3;
$token = $self->parse_variable(\$text)
- || return $self->missing($textref, 'variable after \$');
+ || return $self->missing($textref, 'no_variable');
push(@tokens, $token);
}
else {
- return $self->error("no match in parse_string()");
+ # this should never happen (but never say "never" :-)
+ return $self->error_msg( internal_error => 'parse_string()' );
}
}
@@ -561,7 +590,164 @@
+#------------------------------------------------------------------------
+# parse_key($textref)
+#
+# Parse anything that can be used as the key for a hash, parameter name,
+# etc: unquoted identifier word, single or double quoted string.
+#------------------------------------------------------------------------
+
+sub parse_key {
+ my ($self, $textref) = @_;
+
+ $self->debug("parse_key(", $self->next_chunk($textref), ")\n")
+ if $DEBUG;
+
+ # save current string position
+ my $pos = pos $$textref;
+
+ # look for something that can be the LHS of an assignment
+ if ($$textref =~ /$IDENT/cog) {
+ $self->{ key_parsed } = "'$1'";
+ if ($self->{ directives }->{ $1 }) {
+ pos $$textref = $pos;
+ return $self->decline("not a key (got keyword: $1)");
+ }
+ return [ ident => $1 ];
+ }
+ elsif ($$textref =~ /$SQUOTE/cog) {
+ $self->{ key_parsed } = "'$1'";
+ return [ squote => $1 ];
+ }
+ elsif ($$textref =~ /$DQUOTE/cog) {
+ $self->{ key_parsed } = "\"$1\"";
+ my $text = $1;
+ my $string = $self->parse_string(\$text) || return;
+ return [ dquote => $string ];
+ }
+
+ pos $$textref = $pos;
+ return $self->decline('not a key');
+}
+
+
+#------------------------------------------------------------------------
+# parse_path($textref, %options)
+#
+# Parse a template path. This can be an unquoted filename containing
+# word characters plus a few others ('.' and '/' for example), a
+# single quoted or double quoted string, or a variable reference
+# explicitly prefixed with '$'. The 'static' option can be set to
+# restrict the method to only parse static values: filenames, single
+# quoted strings, and double quoted string that contain only text -
+# no double quoted or naked variables allowed!
+#------------------------------------------------------------------------
+
+sub parse_path {
+ my ($self, $textref, %opts) = @_;
+ my $term;
+
+ $self->debug("parse_path('", $self->next_chunk($textref), "')\n")
+ if $DEBUG;
+
+ my $pos = pos $$textref;
+
+ if ($$textref =~ /$FILENAME/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 ];
+ }
+ elsif ($$textref =~ /$SQUOTE/cog) {
+ $term = [ squote => $1 ];
+ }
+ elsif ($$textref =~ /$DQUOTE/cog) {
+ my $text = $1;
+ $term = $self->parse_string(\$text);
+
+ # if the 'static' option is set then check that the double quoted
+ # string contains static text only, and no variable references
+ if ($opts{ static }) {
+ foreach (@$term) {
+ return $self->error_msg('no_static_variables')
+ if ref $_;
+ }
+ }
+ $term = [ dquote => $term ];
+ }
+ elsif ($$textref =~ /$INTERP/cog) {
+ # similarly, we only allow variable references if the static
+ # option isn't set
+ if ($opts{static}) {
+ return $self->error_msg('no_static_variables');
+ }
+ else {
+ $term = $self->parse_variable($textref)
+ || return $self->missing($textref, 'no_variable');
+ }
+ }
+ else {
+ return $self->decline('not a path');
+ }
+
+ return $term;
+}
+
+
+#------------------------------------------------------------------------
+# parse_static_path($textref)
+#
+# Wrapper around parse_path() which sets the 'static' option to 1.
+#------------------------------------------------------------------------
+
+sub parse_static_path {
+ my ($self, $textref) = @_;
+ return $self->parse_path($textref, static => 1)
+ || $self->decline('not a static path');
+}
+
+
+
+sub parse_name {
+ my $self = shift;
+ my ($pkg, $file, $line) = caller(0);
+ return $self->error("parse_name() has been changed to parse_statc_path()\n",
+ "please fix the code calling it at $file line $line\n");
+}
+
+sub parse_template_name {
+ my $self = shift;
+ my ($pkg, $file, $line) = caller(0);
+ return $self->error("parse_template_name() has been changed to parse_name()\n",
+ "please fix the code calling it at $file line $line\n");
+}
+
+sub parse_filename {
+ my ($self, $textref) = @_;
+ my ($pkg, $file, $line) = caller(0);
+ return $self->error("parse_filename() has been deprecated\n",
+ "please fix the code calling it at $file line $line\n");
+}
+
+
+
+
+#------------------------------------------------------------------------
+# parse_paths()
+#
+# Parse one or more template paths separated by '+'.
+#------------------------------------------------------------------------
+
+sub parse_paths {
+ my $self = shift;
+ return $self->error("parse_paths() not yet implemented");
+}
+
+
+
#========================================================================
# variables
#========================================================================
@@ -592,7 +778,7 @@
$self->debug("found KEYWORD at variable position, declining\n")
if $DEBUG;
pos $$textref = $pos;
- return $self->decline("found keyword for next directive: $ident");
+ return $self->decline("not a variable (got keyword: $ident)");
}
$term = [ ident => $ident ];
@@ -602,7 +788,7 @@
$args = $self->parse_args($textref) || return $args;
# moved from parse_args()
- return $self->missing($textref, "')' at end of argument list")
+ return $self->missing($textref, 'no_end_paren')
unless ($$textref =~ /$ENDPAREN/cog);
}
}
@@ -617,7 +803,7 @@
if ( $$textref =~ /$DOTOP/cog ) {
# TODO: not sure why this is set to $term which is subsequently ignored...
$self->parse_varnodes($textref, $terms)
- || return $self->missing($textref, "item after '.'");
+ || return $self->missing($textref, 'no_dot_item');
}
return [ variable => $terms ];
@@ -641,7 +827,7 @@
do {
($node = $self->parse_varnode($textref))
|| return @$nodes
- ? $self->missing($textref, "item after '.'")
+ ? $self->missing($textref, 'no_dot_item')
: $node;
push(@$nodes, $node);
}
@@ -694,22 +880,22 @@
}
elsif ($$textref =~ /$LIST/cog) {
$term = $self->parse_list($textref) || return;
- return $self->unexpected($textref, 'in list definition [ ... ]')
+ return $self->unexpected($textref, 'in_list_def')
unless $$textref =~ /$ENDLIST/cog;
}
# elsif ($$textref =~ /$HASH/cog) {
# $term = $self->parse_hash($textref) || return;
-# return $self->unexpected($textref, 'in hash definition { ... }')
+# return $self->unexpected($textref, 'in_hash_def')
# unless $$textref =~ /$ENDHASH/cog;
# }
elsif ($$textref =~ /$EMBED/cog) {
my $text = $1;
($term = $self->parse_variable(\$text))
- || return $self->missing($textref, "variable in '\${ }'");
+ || return $self->missing($textref, 'no_embedded');
}
elsif ($$textref =~ /$INTERP/cog) {
($term = $self->parse_variable($textref))
- || return $self->missing($textref, "variable after '\$'");
+ || return $self->missing($textref, 'no_variable');
}
else {
return $self->decline('not a variable node');
@@ -719,7 +905,7 @@
$args = $self->parse_args($textref) || return;
# moved from parse_args
- return $self->missing($textref, "')' at end of argument list")
+ return $self->missing($textref, 'no_end_paren')
unless ($$textref =~ /$ENDPAREN/cog);
}
@@ -758,8 +944,7 @@
push(@items, [ range => $item, $end ]);
}
else {
- return $self->unexpected($textref,
- "after '$range' where expression expected");
+ return $self->unexpected($textref, bad_expr_after => $range);
}
}
else {
@@ -789,12 +974,11 @@
# look up regex to match corresponding right bracket
my $regex = $RBRACKET->{ $left }
- || return $self->error("no right bracket defined to match $1\n");
-
+ || return $self->error_msg( no_right_bracket => $1 );
my $right = $BRACKETS->{ $left };
# match text up to right bracket
- return $self->missing($textref, "$right after 'qw$left'")
+ return $self->missing($textref, missing_after => $right, "qw$left")
unless $$textref =~ /$regex/gc;
return [ qwlist => $left, $1, $right ];
@@ -820,8 +1004,7 @@
while ($key = $self->parse_key($textref)) {
$value = $self->parse_assign_expr($textref)
- || return $self->missing($textref,
- "assignment after hash key $self->{ key }");
+ || return $self->missing($textref, no_hash_assign => $self->{ key_parsed });
push(@hash, [ $key, $value ]);
# skip comma and/or whitespace
@@ -836,47 +1019,6 @@
#------------------------------------------------------------------------
-# parse_key($textref)
-#
-# Parse anything that can be used as the key for a hash, parameter name,
-# etc: unquoted identifier word, single or double quoted string.
-#------------------------------------------------------------------------
-
-sub parse_key {
- my ($self, $textref) = @_;
-
- $self->debug("parse_key(", $self->next_chunk($textref), ")\n")
- if $DEBUG;
-
- # save current string position
- my $pos = pos $$textref;
-
- # look for something that can be the LHS of an assignment
- if ($$textref =~ /$IDENT/cog) {
- $self->{ key } = "'$1'";
- if ($self->{ directives }->{ $1 }) {
- pos $$textref = $pos;
- return $self->decline("found directive keyword: $1");
- }
- return [ ident => $1 ];
- }
- elsif ($$textref =~ /$SQUOTE/cog) {
- $self->{ key } = "'$1'";
- return [ squote => $1 ];
- }
- elsif ($$textref =~ /$DQUOTE/cog) {
- $self->{ key } = "\"$1\"";
- my $text = $1;
- my $string = $self->parse_string(\$text) || return;
- return [ dquote => $string ];
- }
-
- pos $$textref = $pos;
- return $self->decline("not a key");
-}
-
-
-#------------------------------------------------------------------------
# parse_args($textref)
#
# Parse the contents of a parenthesised argument list.
@@ -953,8 +1095,7 @@
while ($key = $self->parse_key($textref)) {
$value = $self->parse_assign_expr($textref)
- || return $self->missing($textref,
- "assignment after parameter $self->{ key }");
+ || return $self->missing($textref, no_param_assign => $self->{ key_parsed });
push(@$params, [ tuple => $key, $value ]);
# skip comma and/or whitespace
@@ -968,8 +1109,6 @@
}
-
-
#------------------------------------------------------------------------
# parse_parens($textref)
#
@@ -993,44 +1132,10 @@
}
-#------------------------------------------------------------------------
-# parse_assign($textref)
-#
-# Parses an assignement statement of the form: variable =>? expression
-#------------------------------------------------------------------------
-
-sub parse_assign {
- my ($self, $textref) = @_;
- my ($var, $op, $value, $assign);
-
- $self->debug("parse_assign()\n") if $DEBUG;
- # skip any leading whitespace
- $$textref =~ /$self->{ wspace }/cg;
-
- # save string position in case we need to backtrack
- my $pos = pos $$textref;
-
- # look for a variable
- if ($var = $self->parse_variable($textref)) {
- if ($$textref =~ /$self->{ assign }/cg) {
- $op = $1;
- $self->debug(" - assign ($op)\n") if $DEBUG;
-
- $value = $self->parse_expression($textref)
- || return $self->unexpected($textref,
- "after '$op' where expression expected");
- return [ assign => $var, $value ];
- }
- }
-
- # rewind string position to start of variable
- $self->debug("- not assign, backtracking\n") if $DEBUG;
-
- pos $$textref = $pos;
-
- return $self->decline('not an assignment');
-}
+#========================================================================
+# assignments
+#========================================================================
#------------------------------------------------------------------------
@@ -1050,9 +1155,9 @@
$$textref =~ /$self->{ wspace }/cg;
if ($$textref =~ /$self->{ assign }/cg) {
- $op = $1;
+ $op = $self->{ assign_parsed } = $1;
return $self->parse_expression($textref)
- || $self->missing($textref, "expression after '$op'");
+ || $self->missing($textref, no_expr_after => $op);
}
else {
return $self->decline('not an assignment');
@@ -1068,22 +1173,104 @@
#------------------------------------------------------------------------
sub parse_ident_assign_expr {
- my ($self, $textref) = @_;
- my ($ident, $expr);
+ my ($self, $textref, %opts) = @_;
$self->debug("parse_ident_assign_expr(",
$self->next_chunk($textref), ")") if $DEBUG;
$$textref =~ /$self->{ wspace }/cgx;
+
+ my $pos = pos $$textref;
+ my $ident = $self->parse_ident($textref) || return;
+
+ if (my $expr = $self->parse_assign_expr($textref, %opts)) {
+ return [ $ident, $expr ];
+ }
+ elsif ($opts{ required }) {
+ return $self->missing($textref, no_ident_assign => $ident);
+ }
+ else {
+ pos $$textref = $pos;
+ return $self->decline('not an assignment');
+ }
+}
+
+
+#------------------------------------------------------------------------
+# parse_key_assign_expr($textref)
+#
+# Parses an assignment of a hash key (ident, single or double quoted) to
+# an expression, e.g. "x = 10", "y => x", "z = x || y".
+#------------------------------------------------------------------------
+
+sub parse_key_assign_expr {
+ my ($self, $textref, %opts) = @_;
+
+ $self->debug("parse_key_assign_expr(",
+ $self->next_chunk($textref), ")") if $DEBUG;
+
+ $$textref =~ /$self->{ wspace }/cgx;
+
+ my $pos = pos $$textref;
+ my $key = $self->parse_key($textref) || return;
- $ident = $self->parse_ident($textref) || return;
- $expr = $self->parse_assign_expr($textref)
- || return $self->missing($textref, "assignment after identifier '$ident'");
- return [ $ident, $expr ];
+ if (my $expr = $self->parse_assign_expr($textref)) {
+ return [ $key, $expr ];
+ }
+ elsif ($opts{ required }) {
+ return $self->missing($textref, no_key_assign => $self->{ key_parsed });
+ }
+ else {
+ pos $$textref = $pos;
+ return $self->decline('not an assignment');
+ }
}
#------------------------------------------------------------------------
+# parse_var_assign_expr($textref)
+#
+# Parses an assignement statement of the form: variable =>? expression
+#------------------------------------------------------------------------
+
+sub parse_var_assign_expr {
+ my ($self, $textref, %opts) = @_;
+
+ $self->debug("parse_var_assign_expr()\n") if $DEBUG;
+
+ $$textref =~ /$self->{ wspace }/cg;
+
+ my $pos = pos $$textref;
+ my $var = $self->parse_variable($textref) || return;
+
+ if (my $expr = $self->parse_assign_expr($textref)) {
+ return [ $var, $expr ];
+ }
+ elsif ($opts{ required }) {
+ return $self->missing($textref, 'no_var_assign');
+ }
+ else {
+ pos $$textref = $pos;
+ return $self->decline('not an assignment');
+ }
+}
+
+
+
+sub parse_assign {
+ my $self = shift;
+ my $expr = $self->parse_var_assign_expr(@_) || return;
+ unshift(@$expr, 'assign');
+ return $expr;
+ my ($pkg, $file, $line) = caller(0);
+ return $self->error("deprecated parse_assign() method called at $file line $line\n");
+}
+
+
+
+
+
+#------------------------------------------------------------------------
# parse_ident_args($text)
#
# Parser a simple identifier (e.g. variable name) optionally followed by
@@ -1097,23 +1284,11 @@
$self->debug("parse_ident_args(", $self->next_chunk($textref), ")\n")
if $DEBUG;
-
- my $pos = pos $$textref;
-
- # look for an identifier
- return $self->decline('no identifier')
- unless $$textref =~ /$IDENT/cog;
- my $ident = $1;
+ my $pos = pos $$textref;
+ my $ident = $self->parse_ident($textref) || return;
+ my $term = [ ident => $ident ];
- if ($self->{ directives }->{ $ident }) {
- $self->debug("found directive keyword, declining\n") if $DEBUG;
- pos $$textref = $pos;
- return $self->decline("no identifier, got directive keyword: $ident");
- }
-
- my $term = [ ident => $ident ];
-
# args may follow
if ($$textref =~ /$PAREN/cog) {
my @args;
@@ -1129,13 +1304,13 @@
# then end of the tag, then report a missing ')', otherwise we
# report that a non-identifier was found in the args list
if ($$textref =~ / (?= \G \s* $ ) /cgsx) {
- return $self->error('unexpected end of text in argument list');
+ return $self->error_msg('args_end_text');
}
elsif ($tag_end && ($$textref =~ /$tag_end/cg)) {
- return $self->missing($textref, "')' at end of argument list");
+ return $self->missing($textref, 'no_end_paren');
}
else {
- return $self->unexpected($textref, 'in argument list');
+ return $self->unexpected($textref, 'in_args');
}
}
@@ -1153,94 +1328,6 @@
}
-
-
-#------------------------------------------------------------------------
-# parse_filename($textref)
-#
-# filename: FILENAME
-# | QUOTED
-# | LITERAL
-#------------------------------------------------------------------------
-
-sub parse_filename {
- my ($self, $textref) = @_;
- my $term;
-
- $self->debug("parse_filename('", $self->next_chunk($textref), "')\n")
- if $DEBUG;
-
- my $pos = pos $$textref;
-
- if ($$textref =~ /$FILENAME/cog) {
- if ($self->{ directives }->{ $1 }) {
- $self->debug("found directive keyword, declining\n") if $DEBUG;
- pos $$textref = $pos;
- return $self->decline("no filename, got directive keyword: $1");
- }
- $term = [ filename => $1 ];
- }
- elsif ($$textref =~ /$SQUOTE/cog) {
- $term = [ squote => $1 ];
- }
- elsif ($$textref =~ /$DQUOTE/cog) {
- # we'll accept double quote strings, but only if they contain static
- # text and don't have any embedded variables in them.
- my $text = $1;
- $term = $self->parse_string(\$text);
- foreach (@$term) {
- return $self->error('invalid variables in double quoted file name')
- if ref $_;
- }
- $term = [ dquote => join('', @$term) ];
- }
- else {
- return $self->decline('no file name');
- }
-
- return $term;
-}
-
-
-
-#------------------------------------------------------------------------
-# parse_template_name($textref)
-#
-# filename: FILENAME
-# | QUOTED
-# | LITERAL
-# | $variable
-#------------------------------------------------------------------------
-
-sub parse_template_name {
- my ($self, $textref) = @_;
- my $term;
-
- if ($$textref =~ /$FILENAME/cog) {
- $term = [ filename => $1 ];
- }
- elsif ($$textref =~ /$SQUOTE/cog) {
- $term = [ squote => $1 ];
- }
- elsif ($$textref =~ /$DQUOTE/cog) {
- my $text = $1;
- $term = $self->parse_string(\$text);
- $term = [ dquote => $term ];
- }
- elsif ($$textref =~ /$INTERP/cog) {
- $self->debug("parsing filename variable\n") if $DEBUG;
- $term = $self->parse_variable($textref)
- || return $self->missing($textref, "variable after '\$'");
- }
- else {
- return $self->decline('not a template name');
- }
-
- return $term;
-}
-
-
-
#------------------------------------------------------------------------
# parse_whitespace($text)
#
@@ -1321,21 +1408,21 @@
#------------------------------------------------------------------------
-# unexpected(\$text, $message)
+# unexpected(\$text, $code, @args)
#
# Error reporting method.
#------------------------------------------------------------------------
sub unexpected {
- my ($self, $textref, @message) = @_;
+ my ($self, $textref, $code, @args) = @_;
my $next = $self->next_token($textref);
$next = length $next ? "'$next'" : 'end of statement';
- return $self->error("unexpected $next ", @message);
+ return $self->error_msg($code, $next, @args);
}
#------------------------------------------------------------------------
-# missing(\$text, $message)
+# missing(\$text, $code, @args)
#
# Error checking and reporting method. If $value is defined (but
# usually false) then it indicates that the parser has declined to parse
@@ -1345,10 +1432,10 @@
#------------------------------------------------------------------------
sub missing {
- my ($self, $textref, @error) = @_;
+ my ($self, $textref, $code, @args) = @_;
my $next = $self->next_token($textref);
- $next = defined $next && length $next ? " (got '$next')" : '';
- return $self->error('missing ', @error, $next);
+ $next = defined $next && length $next ? "got '$next'" : 'end of statement';
+ return $self->error_msg($code, @args, $next);
}
@@ -2063,9 +2150,58 @@
Parses the contents of a double quoted string. This does most of the
dirty work for parse_dquote().
+
+=head2 parse_key(\$text)
-=head2 parse_name(\$text)
+This method parses a hash key. This can be an unquoted identifier, a
+single or double quoted string.
+For example:
+
+ foo
+ 'foo'
+ "foo"
+ "foo$bar"
+ "${foo}bar"
+
+=head2 parse_path(\$text, %options)
+
+This method parses a template path containing any combination of
+alphanumeric characters, C<_>, C</>, C<.> or C<:>.
+
+For example:
+
+ header
+ my_header
+ my/header
+ my/header.html
+ file:my/header.html
+ http://example.com/templates/header.html
+ site_header
+ index.html
+
+It can also be expressed as a single or double quoted string. Double
+quoted strings can contain embedded variables (but see the C<static>
+option described below).
+
+ 'header'
+ "header"
+ "header.$ext"
+ "${filename}.$ext"
+
+The path can also be specified by reference to a variable. The variable
+should be prefixed with C<$>, just as you would when embedding a variable
+in a double quoted string.
+
+ $filename
+ $my.templates.header
+
+The C<static> option can be set to indicate that the method should only
+accept static paths that don't contain any variable references, either
+
+
+
+
TODO: this method needs work. should handle name+name+name and other
stuff.
@@ -2079,6 +2215,8 @@
"my$file"
$filename
+=head2 parse_static_path(\$text)
+
TODO: more docs on this
=head2 parse_variable(\$text)
@@ -2215,11 +2353,6 @@
]
]
-=head2 parse_key(\$text)
-
-TODO: method for parsing a hash key. can be an unquoted identifier, a
-single or double quoted string, of variable node and any arguments
-
=head2 parse_args(\$text)
TODO: parse a list of arguments, as enclosed by parens. Only parses the
@@ -2240,14 +2373,6 @@
TODO: Parse an assignment or expression enclosed in parentheses.
-=head2 parse_assign(\$text)
-
-TODO: parse an assignment of variable to expression, such as in the SET
-directive.
-
- foo = bar
- wiz.waz = a < b ? c : d
-
=head2 parse_assign_expr(\$text)
TODO: parse an assignment to an expression
@@ -2263,6 +2388,15 @@
a = 10
b = 20
+=head2 parse_assign(\$text)
+
+TODO: parse an assignment of variable to expression, such as in the SET
+directive.
+
+ foo = bar
+ wiz.waz = a < b ? c : d
+
+
=head2 parse_ident_args(\$text)
TODO: parse an identifer followed by an optional argument list
@@ -2351,9 +2485,16 @@
When called without any arguments, the method returns the error message
most recently set by a call to error() (with arguments, of course) or
decline().
+
+=head2 error_msg($code, @args)
+
+TODO: this is used instead of error() to allow us to localise error
+messages, and simplify error handling in general.
-=head2 missing(\$text, $thing)
+=head2 missing(\$text, $code, @args)
+TODO: this has changed - now a wrapper around error_msg()
+
This is a wrapper around the error() method which constructs an error
message of the form "missing $thing (got 'blah')". The first argument
is a reference to the current input text string. The method uses this
@@ -2382,6 +2523,8 @@
=head2 unexpected(\$text, $message)
+TODO: this has changed - now a wrapper around error_msg()
+
Like the missing() method, this provides a wrapper around the error()
method.
@@ -2433,7 +2576,7 @@
=head1 VERSION
-$Revision: 1.17 $
+$Revision: 1.18 $
=head1 COPYRIGHT