fixed nested block definitions with a parent call (closes #45)
authorFabien Potencier <fabien.potencier@gmail.com>
Thu, 29 Apr 2010 05:58:52 +0000 (07:58 +0200)
committerFabien Potencier <fabien.potencier@gmail.com>
Thu, 29 Apr 2010 05:58:52 +0000 (07:58 +0200)
CHANGELOG
lib/Twig/Parser.php
lib/Twig/TokenParser/Block.php
lib/Twig/TokenParser/Parent.php
test/fixtures/tags/inheritance/parent_nested.test [new file with mode: 0644]

index c7d7143..c005080 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,6 @@
 * 0.9.6-DEV
 
+ * fixed nested block definitions with a parent call (rarely useful but nonetheless supported now)
  * added the cycle filter
  * fixed the Lexer when mbstring.func_overload is used with an mbstring.internal_encoding different from ASCII
  * added a long-syntax for the set tag ({% set foo %}...{% endset %})
index 29d60ef..03a7621 100644 (file)
@@ -17,7 +17,7 @@ class Twig_Parser
   protected $visitors;
   protected $expressionParser;
   protected $blocks;
-  protected $currentBlock;
+  protected $blockStack;
   protected $macros;
   protected $env;
 
@@ -63,7 +63,7 @@ class Twig_Parser
     $this->extends = null;
     $this->blocks = array();
     $this->macros = array();
-    $this->currentBlock = null;
+    $this->blockStack = array();
 
     try
     {
@@ -170,14 +170,24 @@ class Twig_Parser
     $this->visitors[] = $visitor;
   }
 
-  public function getCurrentBlock()
+  public function getBlockStack()
   {
-    return $this->currentBlock;
+    return $this->blockStack;
   }
 
-  public function setCurrentBlock($name)
+  public function peekBlockStack()
   {
-    $this->currentBlock = $name;
+    return $this->blockStack[count($this->blockStack) - 1];
+  }
+
+  public function popBlockStack()
+  {
+    array_pop($this->blockStack);
+  }
+
+  public function pushBlockStack($name)
+  {
+    $this->blockStack[] = $name;
   }
 
   public function hasBlock($name)
index 0d35aba..ea61515 100644 (file)
@@ -14,20 +14,13 @@ class Twig_TokenParser_Block extends Twig_TokenParser
   public function parse(Twig_Token $token)
   {
     $lineno = $token->getLine();
-
     $stream = $this->parser->getStream();
     $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
     if ($this->parser->hasBlock($name))
     {
       throw new Twig_SyntaxError("The block '$name' has already been defined", $lineno);
     }
-
-    if (null !== $current = $this->parser->getCurrentBlock())
-    {
-      throw new Twig_SyntaxError("Blocks cannot be nested (you are trying to define a '$name' block inside the '$current' block)", $lineno);
-    }
-
-    $this->parser->setCurrentBlock($name);
+    $this->parser->pushBlockStack($name);
 
     if ($stream->test(Twig_Token::BLOCK_END_TYPE))
     {
@@ -54,7 +47,7 @@ class Twig_TokenParser_Block extends Twig_TokenParser
 
     $block = new Twig_Node_Block($name, $body, $lineno);
     $this->parser->setBlock($name, $block);
-    $this->parser->setCurrentBlock(null);
+    $this->parser->popBlockStack();
 
     return new Twig_Node_BlockReference($name, $lineno, $this->getTag());
   }
index 9771488..5cd7b98 100644 (file)
@@ -13,13 +13,13 @@ class Twig_TokenParser_Parent extends Twig_TokenParser
 {
   public function parse(Twig_Token $token)
   {
-    if (null === $this->parser->getCurrentBlock())
+    if (!count($this->parser->getBlockStack()))
     {
       throw new Twig_SyntaxError('Calling "parent" outside a block is forbidden', $token->getLine());
     }
     $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
 
-    return new Twig_Node_Parent($this->parser->getCurrentBlock(), $token->getLine(), $this->getTag());
+    return new Twig_Node_Parent($this->parser->peekBlockStack(), $token->getLine(), $this->getTag());
   }
 
   public function getTag()
diff --git a/test/fixtures/tags/inheritance/parent_nested.test b/test/fixtures/tags/inheritance/parent_nested.test
new file mode 100644 (file)
index 0000000..1a5cf44
--- /dev/null
@@ -0,0 +1,27 @@
+--TEST--
+"extends" tag
+--TEMPLATE--
+{% extends "foo.twig" %}
+
+{% block content %}
+  {% block inside %}
+    INSIDE OVERRIDDEN
+  {% endblock %}
+
+  BEFORE
+  {% parent %}
+  AFTER
+{% endblock %}
+--TEMPLATE(foo.twig)--
+{% block content %}
+  BAR
+{% endblock %}
+--DATA--
+return array()
+--EXPECT--
+
+INSIDE OVERRIDDEN
+  
+  BEFORE
+    BAR
+  AFTER