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.
$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;
}
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)
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)
// 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;
}