refactored 'defined' test and 'default' filter
authorFabien Potencier <fabien.potencier@gmail.com>
Thu, 6 Oct 2011 14:37:14 +0000 (16:37 +0200)
committerFabien Potencier <fabien.potencier@gmail.com>
Sat, 8 Oct 2011 12:27:18 +0000 (14:27 +0200)
Node manipulations have been moved outside the compile() method.
That's needed if we want to be able to visit all nodes that will be
compiled.

lib/Twig/ExpressionParser.php
lib/Twig/Node/Expression/Filter.php
lib/Twig/Node/Expression/Test.php

index 97c8431..b7ff70d 100644 (file)
@@ -320,6 +320,16 @@ class Twig_ExpressionParser
 
             $node = new Twig_Node_Expression_Filter($node, $name, $arguments, $token->getLine(), $tag);
 
+            // The default filter is intercepted when the filtered value
+            // is a name (like obj) or an attribute (like obj.attr)
+            // In such a case, it's compiled to {{ obj is defined ? obj|default('bar') : 'bar' }}
+            if ('default' === $token->getValue() && ($node->getNode('node') instanceof Twig_Node_Expression_Name || $node->getNode('node') instanceof Twig_Node_Expression_GetAttr)) {
+                $test = new Twig_Node_Expression_Test(clone $node->getNode('node'), 'defined', new Twig_Node(), $node->getLine());
+                $default = count($node->getNode('arguments')) ? $node->getNode('arguments')->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine());
+
+                $node = new Twig_Node_Expression_Conditional($test, $node, $default, $node->getLine());
+            }
+
             if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
                 break;
             }
index 101e6df..bff1a67 100644 (file)
@@ -23,32 +23,7 @@ class Twig_Node_Expression_Filter extends Twig_Node_Expression
             throw new Twig_Error_Syntax(sprintf('The filter "%s" does not exist', $name), $this->getLine());
         }
 
-        $node = $this->getNode('node');
-
-        // The default filter is intercepted when the filtered value
-        // is a name (like obj) or an attribute (like obj.attr)
-        // In such a case, it's compiled to {{ obj is defined ? obj|default('bar') : 'bar' }}
-        if ('default' === $name && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) {
-            $compiler
-                ->raw('((')
-                ->subcompile(new Twig_Node_Expression_Test($node, 'defined', new Twig_Node(), $this->getLine()))
-                ->raw(') ? (')
-            ;
-
-            $this->compileFilter($compiler, $filter);
-
-            $compiler->raw(') : (');
-
-            if ($this->getNode('arguments')->hasNode(0)) {
-                $compiler->subcompile($this->getNode('arguments')->getNode(0));
-            } else {
-                $compiler->string('');
-            }
-
-            $compiler->raw('))');
-        } else {
-            $this->compileFilter($compiler, $filter);
-        }
+        $this->compileFilter($compiler, $filter);
     }
 
     protected function compileFilter(Twig_Compiler $compiler, Twig_FilterInterface $filter)
index ef35df6..1c000ac 100644 (file)
@@ -13,6 +13,15 @@ class Twig_Node_Expression_Test extends Twig_Node_Expression
     public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
     {
         parent::__construct(array('node' => $node, 'arguments' => $arguments), array('name' => $name), $lineno);
+
+        // defined is a special case
+        if ('defined' === $name) {
+            if ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr) {
+                $node->setAttribute('is_defined_test', true);
+            } else {
+                throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine());
+            }
+        }
     }
 
     public function compile(Twig_Compiler $compiler)
@@ -27,13 +36,8 @@ class Twig_Node_Expression_Test extends Twig_Node_Expression
 
         // defined is a special case
         if ('defined' === $name) {
-            if ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr) {
-                $node->setAttribute('is_defined_test', true);
-                $compiler->subcompile($node);
-                $node->removeAttribute('is_defined_test');
-            } else {
-                throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine());
-            }
+            $compiler->subcompile($node);
+
             return;
         }