From: nikic <+@ni-po.com> Date: Thu, 9 Jun 2011 18:50:48 +0000 (+0200) Subject: Make `a.b is defined` not throw an exception if a is not defined (in strict mode) X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=e7604832875a3bf42b57e396ff653b9ac7b774c2;p=web%2Fkonrad%2Ftwig.git Make `a.b is defined` not throw an exception if a is not defined (in strict mode) --- diff --git a/lib/Twig/Node/Expression/Filter.php b/lib/Twig/Node/Expression/Filter.php index 1632778..101e6df 100644 --- a/lib/Twig/Node/Expression/Filter.php +++ b/lib/Twig/Node/Expression/Filter.php @@ -23,28 +23,28 @@ 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 && ($this->getNode('node') instanceof Twig_Node_Expression_Name || $this->getNode('node') instanceof Twig_Node_Expression_GetAttr)) { - $compiler->raw('(('); - if ($this->getNode('node') instanceof Twig_Node_Expression_Name) { - $testMap = $compiler->getEnvironment()->getTests(); - $compiler - ->raw($testMap['defined']->compile().'(') - ->repr($this->getNode('node')->getAttribute('name')) - ->raw(', $context)') - ; - } elseif ($this->getNode('node') instanceof Twig_Node_Expression_GetAttr) { - $this->getNode('node')->setAttribute('is_defined_test', true); - $compiler->subcompile($this->getNode('node')); - $this->getNode('node')->removeAttribute('is_defined_test'); - } + 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(') ? (') + ; - $compiler->raw(') ? ('); $this->compileFilter($compiler, $filter); + $compiler->raw(') : ('); - $compiler->subcompile($this->getNode('arguments')->getNode(0)); + + if ($this->getNode('arguments')->hasNode(0)) { + $compiler->subcompile($this->getNode('arguments')->getNode(0)); + } else { + $compiler->string(''); + } + $compiler->raw('))'); } else { $this->compileFilter($compiler, $filter); @@ -57,10 +57,9 @@ class Twig_Node_Expression_Filter extends Twig_Node_Expression ->raw($filter->compile().'(') ->raw($filter->needsEnvironment() ? '$this->env, ' : '') ->raw($filter->needsContext() ? '$context, ' : '') + ->subcompile($this->getNode('node')) ; - $this->getNode('node')->compile($compiler); - foreach ($this->getNode('arguments') as $node) { $compiler ->raw(', ') diff --git a/lib/Twig/Node/Expression/GetAttr.php b/lib/Twig/Node/Expression/GetAttr.php index 0ac04f6..2208c9e 100644 --- a/lib/Twig/Node/Expression/GetAttr.php +++ b/lib/Twig/Node/Expression/GetAttr.php @@ -18,9 +18,20 @@ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression public function compile(Twig_Compiler $compiler) { + $compiler->raw('$this->getAttribute('); + + if ($this->hasAttribute('is_defined_test')) { + $compiler->subcompile(new Twig_Node_Expression_Filter( + $this->getNode('node'), + new Twig_Node_Expression_Constant('default', $this->getLine()), + new Twig_Node(), + $this->getLine() + )); + } else { + $compiler->subcompile($this->getNode('node')); + } + $compiler - ->raw('$this->getAttribute(') - ->subcompile($this->getNode('node')) ->raw(', ') ->subcompile($this->getNode('attribute')) ->raw(', array(') diff --git a/lib/Twig/Node/Expression/Name.php b/lib/Twig/Node/Expression/Name.php index a7194b7..f7d1875 100644 --- a/lib/Twig/Node/Expression/Name.php +++ b/lib/Twig/Node/Expression/Name.php @@ -18,16 +18,26 @@ class Twig_Node_Expression_Name extends Twig_Node_Expression public function compile(Twig_Compiler $compiler) { - if ('_self' === $this->getAttribute('name')) { - $compiler->raw('$this'); - } elseif ('_context' === $this->getAttribute('name')) { - $compiler->raw('$context'); - } elseif ('_charset' === $this->getAttribute('name')) { - $compiler->raw('$this->env->getCharset()'); + static $specialVars = array( + '_self' => '$this', + '_context' => '$context', + '_charset' => '$this->env->getCharset()', + ); + + $name = $this->getAttribute('name'); + + if ($this->hasAttribute('is_defined_test')) { + if (isset($specialVars[$name])) { + $compiler->repr(true); + } else { + $compiler->raw('array_key_exists(')->repr($name)->raw(', $context)'); + } + } elseif (isset($specialVars[$name])) { + $compiler->raw($specialVars[$name]); } elseif ($compiler->getEnvironment()->isStrictVariables()) { - $compiler->raw(sprintf('$this->getContext($context, \'%s\')', $this->getAttribute('name'))); + $compiler->raw(sprintf('$this->getContext($context, \'%s\')', $name)); } else { - $compiler->raw(sprintf('(isset($context[\'%s\']) ? $context[\'%s\'] : null)', $this->getAttribute('name'), $this->getAttribute('name'))); + $compiler->raw(sprintf('(isset($context[\'%s\']) ? $context[\'%s\'] : null)', $name, $name)); } } } diff --git a/lib/Twig/Node/Expression/Test.php b/lib/Twig/Node/Expression/Test.php index 204da25..ef35df6 100644 --- a/lib/Twig/Node/Expression/Test.php +++ b/lib/Twig/Node/Expression/Test.php @@ -22,19 +22,15 @@ class Twig_Node_Expression_Test extends Twig_Node_Expression throw new Twig_Error_Syntax(sprintf('The test "%s" does not exist', $this->getAttribute('name')), $this->getLine()); } + $name = $this->getAttribute('name'); + $node = $this->getNode('node'); + // defined is a special case - if ('defined' === $this->getAttribute('name')) { - if ($this->getNode('node') instanceof Twig_Node_Expression_Name) { - $compiler - ->raw($testMap['defined']->compile().'(') - ->repr($this->getNode('node')->getAttribute('name')) - ->raw(', $context)') - ; - } elseif ($this->getNode('node') instanceof Twig_Node_Expression_GetAttr) { - $this->getNode('node')->setAttribute('is_defined_test', true); - $compiler - ->subcompile($this->getNode('node')) - ; + 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()); } @@ -42,16 +38,16 @@ class Twig_Node_Expression_Test extends Twig_Node_Expression } $compiler - ->raw($testMap[$this->getAttribute('name')]->compile().'(') - ->subcompile($this->getNode('node')) + ->raw($testMap[$name]->compile().'(') + ->subcompile($node) ; if (null !== $this->getNode('arguments')) { $compiler->raw(', '); $max = count($this->getNode('arguments')) - 1; - foreach ($this->getNode('arguments') as $i => $node) { - $compiler->subcompile($node); + foreach ($this->getNode('arguments') as $i => $arg) { + $compiler->subcompile($arg); if ($i != $max) { $compiler->raw(', ');