package Squirrel::Template::Expr;
use strict;
-our $VERSION = "1.011";
+our $VERSION = "1.012";
package Squirrel::Template::Expr::Eval;
use Scalar::Util ();
my $true = $self->_parse_or($tok);
my $colon = $tok->get;
$colon->[0] eq 'op:'
- or die [ error => "Expected : for ? : operator but found $tok->[1]" ];
+ or die [ error => "Expected : for ? : operator but found $colon->[0]" ];
my $false = $self->_parse_cond($tok);
$result = [ cond => $result, $true, $false ];
# get the real name
$name = $tok->get;
$name->[0] eq 'id'
- or die [ error => "Expected an identifer after .\$ but found $name->[1]" ];
+ or die [ error => "Expected an identifier after .\$ but found $name->[1]" ];
my $list = [];
if ($tok->peektype eq 'op(') {
$list = $self->_parse_paren_list($tok, "method");
$result = [ callvar => $name->[2], $result, $list ];
}
else {
- die [ error => "Expected method name or \$var after '.' but found $name->[1]" ];
+ die [ error => "Expected a method name or \$var after '.' but found $name->[1]" ];
}
}
elsif ($next eq 'op[') {
my $index = $self->_parse_expr($tok);
my $close = $tok->get;
$close->[0] eq 'op]'
- or die [ error => "Expected list end ']' but got $close->[0]" ];
+ or die [ error => "Expected closing ']' but got $close->[0]" ];
$result = [ subscript => $result, $index ];
}
elsif ($next eq 'op(') {
}
my $close = $tok->get;
$close->[0] eq 'op]'
- or die [ error => "Expected ] but got $close->[0]" ];
+ or die [ error => "Expected list end ']' but got $close->[0]" ];
return [ list => $list ];
}
elsif ($t->[0] eq 'op{') {
use strict;
use Squirrel::Template::Constants qw(:token :node);
-our $VERSION = "1.015";
+our $VERSION = "1.016";
use constant TOK => 0;
use constant TMPLT => 1;
my $parser = Squirrel::Template::Expr::Parser->new;
my $parsed;
+ local $SIG{__DIE__};
if (eval { $parsed = $parser->parse($expr->[TOKEN_EXPR_EXPR]); 1 }) {
$expr->[NODE_EXPR_EXPR] = $parsed;
$expr->[NODE_EXPR_FORMAT] ||= $self->[TMPLT]{def_format};
my $tokens = Squirrel::Template::Expr::Tokenizer->new($stmt->[TOKEN_EXPR_EXPR]);
my @list;
my $parsed;
+ local $SIG{__DIE__};
my $good = eval {
push @list, $parser->parse_tokens($tokens);
while ($tokens->peektype eq "op;") {
my $parser = Squirrel::Template::Expr::Parser->new;
my $parsed;
+ local $SIG{__DIE__};
if (eval { $parsed = $parser->parse($set->[TOKEN_SET_EXPR]); 1 }) {
$set->[NODE_SET_VAR] = [ split /\./, $set->[TOKEN_SET_VAR] ];
$set->[NODE_SET_EXPR] = $parsed;
}
my $list_expr;
my $parser = Squirrel::Template::Expr::Parser->new;
+ local $SIG{__DIE__};
unless (eval { $list_expr = $parser->parse($for->[TOKEN_FOR_EXPR]); 1 }) {
return $self->_error($for, "Could not parse list for .for: " . (ref $@ ? $@->[0] : $@));
}
my $error;
my $parser = Squirrel::Template::Expr::Parser->new;
my $name_expr;
+ local $SIG{__DIE__};
unless (eval { $name_expr = $parser->parse_tokens($tokens); 1 }) {
return $self->_error($call, "Could not parse expression: ".$@->[1]);
}
my $parser = Squirrel::Template::Expr::Parser->new;
for my $cond (@conds) {
+ local $SIG{__DIE__};
unless (eval { $cond->[2] = $parser->parse($cond->[0][TOKEN_EXT_EXPR]); 1 }) {
$cond->[2] = [ const => "", "" ];
push @errors, $self->_error($cond->[0], ref $@ ? $@->[1] : $@);
my $parser = Squirrel::Template::Expr::Parser->new;
my $cond_expr;
+ local $SIG{__DIE__};
unless (eval { $cond_expr = $parser->parse($while->[TOKEN_EXT_EXPR]); 1 }) {
return $self->_error($while, "Could not parse condition for .while: " . ref $@ ? $@->[0] : $@);
}
my $parser = Squirrel::Template::Expr::Parser->new;
my @result;
my $expr;
+ local $SIG{__DIE__};
unless (eval { $expr = $parser->parse_tokens($tokens); 1 }) {
$$rerror = $self->_error($token, "Could not parse expression list: ".$@->[1]);
return;
--- /dev/null
+#!perl -w
+use strict;
+
+# error handling tests
+use Squirrel::Template;
+use Test::More;
+use Carp qw(confess);
+use Data::Dumper;
+
+my @tests =
+ (
+ {
+ name => "missing : in ?:",
+ template => "<:= foo ? bar :>",
+ errors =>
+ [
+ [ error => '', 1, 'test.tmpl', "Expected : for ? : operator but found eof" ],
+ ],
+ result => q/* Expected : for ? : operator but found eof */,
+ },
+ {
+ name => "unrecognized junk after expr",
+ template => "<:= foo ; :>",
+ errors =>
+ [
+ [ error => '', 1, 'test.tmpl', "Expected eof but found op;" ],
+ ],
+ result => q/* Expected eof but found op; */,
+ },
+ {
+ name => "ranges chained",
+ template => "<:= [ 1...3...4 ] :>",
+ errors =>
+ [
+ [ error => '', 1, 'test.tmpl', "Can't use a range as the start of a range" ],
+ ],
+ result => q/* Can't use a range as the start of a range */,
+ },
+ {
+ name => "name.junk",
+ template => "<:= name.; :>",
+ errors =>
+ [
+ [ error => '', 1, 'test.tmpl', q(Expected a method name or $var after '.' but found ;) ],
+ ],
+ result => q/* Expected a method name or $var after '.' but found ; */,
+ },
+ {
+ name => "name.\$junk",
+ template => "<:= name.\$; :>",
+ errors =>
+ [
+ [ error => '', 1, 'test.tmpl', "Expected an identifier after .\$ but found ;" ],
+ ],
+ result => q/* Expected an identifier after .$ but found ; */,
+ },
+ {
+ name => "unterminated list",
+ template => "<:= [ 1 :>",
+ errors =>
+ [
+ [ error => '', 1, 'test.tmpl', "Expected list end ']' but got eof" ],
+ ],
+ result => q/* Expected list end ']' but got eof */,
+ },
+ {
+ name => "unterminated subscript",
+ template => "<:= name[1 :>",
+ errors =>
+ [
+ [ error => '', 1, 'test.tmpl', "Expected closing ']' but got eof" ],
+ ],
+ result => q/* Expected closing ']' but got eof */,
+ },
+ );
+
+plan tests => 3 * scalar(@tests);
+
+my %acts = ();
+
+my %vars = ();
+
+# the following ensures the code isolates evals from __DIE__handlers
+$SIG{__DIE__} = sub { confess @_ };
+
+for my $test (@tests) {
+ my ($name, $template, $want_errors, $want_result) =
+ @$test{qw/name template errors result/};
+
+ my $t = Squirrel::Template->new;
+ my $result;
+ my $good = eval {
+ $result = $t->replace_template($template, \%acts, undef, 'test.tmpl', \%vars);
+ 1;
+ };
+ ok($good, "$name: compile and run template");
+ is($result, $want_result, "$name: expected template result");
+ is_deeply([ $t->errors ], $want_errors, "$name: expected errors")
+ or note Dumper([$t->errors]);
+}