Skip to content

Commit

Permalink
Make a.b is defined not throw an exception if a is not defined (in …
Browse files Browse the repository at this point in the history
…strict mode)
  • Loading branch information
nikic committed Jun 9, 2011
1 parent cd0e749 commit e760483
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 44 deletions.
35 changes: 17 additions & 18 deletions lib/Twig/Node/Expression/Filter.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,28 @@ public function compile(Twig_Compiler $compiler)
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);
Expand All @@ -57,10 +57,9 @@ protected function compileFilter(Twig_Compiler $compiler, Twig_FilterInterface $
->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(', ')
Expand Down
15 changes: 13 additions & 2 deletions lib/Twig/Node/Expression/GetAttr.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,20 @@ public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $at

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(')
Expand Down
26 changes: 18 additions & 8 deletions lib/Twig/Node/Expression/Name.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,26 @@ public function __construct($name, $lineno)

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));
}
}
}
28 changes: 12 additions & 16 deletions lib/Twig/Node/Expression/Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,32 @@ public function compile(Twig_Compiler $compiler)
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());
}
return;
}

$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(', ');
Expand Down

0 comments on commit e760483

Please sign in to comment.