summaryrefslogtreecommitdiff
path: root/inc/lib/Twig/TokenParser/For.php
diff options
context:
space:
mode:
authorMichael Foster <savetheinternet@tinyboard.org>2013-08-01 15:20:12 -0400
committerMichael Foster <savetheinternet@tinyboard.org>2013-08-01 15:20:12 -0400
commit0fe552857468aa12097a74e08f51f5aaa983be07 (patch)
tree22dbca1be90d7086b20a077752552296abf23325 /inc/lib/Twig/TokenParser/For.php
parent22f3a95e0e421de05a11633eac846df96a2a4768 (diff)
Upgrade Twig library
Diffstat (limited to 'inc/lib/Twig/TokenParser/For.php')
-rw-r--r--inc/lib/Twig/TokenParser/For.php66
1 files changed, 58 insertions, 8 deletions
diff --git a/inc/lib/Twig/TokenParser/For.php b/inc/lib/Twig/TokenParser/For.php
index 5ce82979..98a6d079 100644
--- a/inc/lib/Twig/TokenParser/For.php
+++ b/inc/lib/Twig/TokenParser/For.php
@@ -33,32 +33,41 @@ class Twig_TokenParser_For extends Twig_TokenParser
public function parse(Twig_Token $token)
{
$lineno = $token->getLine();
+ $stream = $this->parser->getStream();
$targets = $this->parser->getExpressionParser()->parseAssignmentExpression();
- $this->parser->getStream()->expect(Twig_Token::OPERATOR_TYPE, 'in');
+ $stream->expect(Twig_Token::OPERATOR_TYPE, 'in');
$seq = $this->parser->getExpressionParser()->parseExpression();
$ifexpr = null;
- if ($this->parser->getStream()->test(Twig_Token::NAME_TYPE, 'if')) {
- $this->parser->getStream()->next();
+ if ($stream->test(Twig_Token::NAME_TYPE, 'if')) {
+ $stream->next();
$ifexpr = $this->parser->getExpressionParser()->parseExpression();
}
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this, 'decideForFork'));
- if ($this->parser->getStream()->next()->getValue() == 'else') {
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+ if ($stream->next()->getValue() == 'else') {
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
$else = $this->parser->subparse(array($this, 'decideForEnd'), true);
} else {
$else = null;
}
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
if (count($targets) > 1) {
$keyTarget = $targets->getNode(0);
+ $keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getLine());
$valueTarget = $targets->getNode(1);
+ $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
} else {
$keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno);
$valueTarget = $targets->getNode(0);
+ $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
+ }
+
+ if ($ifexpr) {
+ $this->checkLoopUsageCondition($stream, $ifexpr);
+ $this->checkLoopUsageBody($stream, $body);
}
return new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, $lineno, $this->getTag());
@@ -74,10 +83,51 @@ class Twig_TokenParser_For extends Twig_TokenParser
return $token->test('endfor');
}
+ // the loop variable cannot be used in the condition
+ protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node)
+ {
+ if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
+ throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition', $node->getLine(), $stream->getFilename());
+ }
+
+ foreach ($node as $n) {
+ if (!$n) {
+ continue;
+ }
+
+ $this->checkLoopUsageCondition($stream, $n);
+ }
+ }
+
+ // check usage of non-defined loop-items
+ // it does not catch all problems (for instance when a for is included into another or when the variable is used in an include)
+ protected function checkLoopUsageBody(Twig_TokenStream $stream, Twig_NodeInterface $node)
+ {
+ if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
+ $attribute = $node->getNode('attribute');
+ if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) {
+ throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition', $attribute->getAttribute('value')), $node->getLine(), $stream->getFilename());
+ }
+ }
+
+ // should check for parent.loop.XXX usage
+ if ($node instanceof Twig_Node_For) {
+ return;
+ }
+
+ foreach ($node as $n) {
+ if (!$n) {
+ continue;
+ }
+
+ $this->checkLoopUsageBody($stream, $n);
+ }
+ }
+
/**
* Gets the tag name associated with this token parser.
*
- * @param string The tag name
+ * @return string The tag name
*/
public function getTag()
{