Make a.b is defined not throw an exception if a is not defined (in strict mode)

This commit is contained in:
nikic
2011-06-09 20:50:48 +02:00
parent cd0e749308
commit e760483287
4 changed files with 61 additions and 45 deletions
+18 -19
View File
@@ -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(') ? (')
;
$this->compileFilter($compiler, $filter);
$compiler->raw(') : (');
if ($this->getNode('arguments')->hasNode(0)) {
$compiler->subcompile($this->getNode('arguments')->getNode(0));
} else {
$compiler->string('');
}
$compiler->raw(') ? (');
$this->compileFilter($compiler, $filter);
$compiler->raw(') : (');
$compiler->subcompile($this->getNode('arguments')->getNode(0));
$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(', ')
+13 -2
View File
@@ -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(')
+18 -8
View File
@@ -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));
}
}
}
+12 -16
View File
@@ -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(', ');