Upgrade Twig library

This commit is contained in:
Michael Foster 2013-08-01 15:20:12 -04:00
parent 22f3a95e0e
commit 0fe5528574
133 changed files with 5080 additions and 1386 deletions

View file

@ -10,9 +10,54 @@
*/
class Twig_Node_Expression_Array extends Twig_Node_Expression
{
protected $index;
public function __construct(array $elements, $lineno)
{
parent::__construct($elements, array(), $lineno);
$this->index = -1;
foreach ($this->getKeyValuePairs() as $pair) {
if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) {
$this->index = $pair['key']->getAttribute('value');
}
}
}
public function getKeyValuePairs()
{
$pairs = array();
foreach (array_chunk($this->nodes, 2) as $pair) {
$pairs[] = array(
'key' => $pair[0],
'value' => $pair[1],
);
}
return $pairs;
}
public function hasElement(Twig_Node_Expression $key)
{
foreach ($this->getKeyValuePairs() as $pair) {
// we compare the string representation of the keys
// to avoid comparing the line numbers which are not relevant here.
if ((string) $key == (string) $pair['key']) {
return true;
}
}
return false;
}
public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null)
{
if (null === $key) {
$key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine());
}
array_push($this->nodes, $key, $value);
}
/**
@ -24,16 +69,16 @@ class Twig_Node_Expression_Array extends Twig_Node_Expression
{
$compiler->raw('array(');
$first = true;
foreach ($this->nodes as $name => $node) {
foreach ($this->getKeyValuePairs() as $pair) {
if (!$first) {
$compiler->raw(', ');
}
$first = false;
$compiler
->repr($name)
->subcompile($pair['key'])
->raw(' => ')
->subcompile($node)
->subcompile($pair['value'])
;
}
$compiler->raw(')');

View file

@ -19,6 +19,10 @@ class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name
*/
public function compile(Twig_Compiler $compiler)
{
$compiler->raw(sprintf('$context[\'%s\']', $this->getAttribute('name')));
$compiler
->raw('$context[')
->string($this->getAttribute('name'))
->raw(']')
;
}
}

View file

@ -17,9 +17,9 @@ class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary
*/
public function compile(Twig_Compiler $compiler)
{
$compiler->raw('floor(');
$compiler->raw('intval(floor(');
parent::compile($compiler);
$compiler->raw(')');
$compiler->raw('))');
}
public function operator(Twig_Compiler $compiler)

View file

@ -13,8 +13,7 @@
/**
* Represents a block call node.
*
* @package twig
* @author Fabien Potencier <fabien@symfony.com>
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Expression_BlockReference extends Twig_Node_Expression
{

View file

@ -0,0 +1,178 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2012 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
{
protected function compileCallable(Twig_Compiler $compiler)
{
$callable = $this->getAttribute('callable');
$closingParenthesis = false;
if ($callable) {
if (is_string($callable)) {
$compiler->raw($callable);
} elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) {
$compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1]));
} else {
$type = ucfirst($this->getAttribute('type'));
$compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name')));
$closingParenthesis = true;
}
} else {
$compiler->raw($this->getAttribute('thing')->compile());
}
$this->compileArguments($compiler);
if ($closingParenthesis) {
$compiler->raw(')');
}
}
protected function compileArguments(Twig_Compiler $compiler)
{
$compiler->raw('(');
$first = true;
if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
$compiler->raw('$this->env');
$first = false;
}
if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
if (!$first) {
$compiler->raw(', ');
}
$compiler->raw('$context');
$first = false;
}
if ($this->hasAttribute('arguments')) {
foreach ($this->getAttribute('arguments') as $argument) {
if (!$first) {
$compiler->raw(', ');
}
$compiler->string($argument);
$first = false;
}
}
if ($this->hasNode('node')) {
if (!$first) {
$compiler->raw(', ');
}
$compiler->subcompile($this->getNode('node'));
$first = false;
}
if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) {
$callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null;
$arguments = $this->getArguments($callable, $this->getNode('arguments'));
foreach ($arguments as $node) {
if (!$first) {
$compiler->raw(', ');
}
$compiler->subcompile($node);
$first = false;
}
}
$compiler->raw(')');
}
protected function getArguments($callable, $arguments)
{
$parameters = array();
$named = false;
foreach ($arguments as $name => $node) {
if (!is_int($name)) {
$named = true;
$name = $this->normalizeName($name);
} elseif ($named) {
throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
}
$parameters[$name] = $node;
}
if (!$named) {
return $parameters;
}
if (!$callable) {
throw new LogicException(sprintf('Named arguments are not supported for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
}
// manage named arguments
if (is_array($callable)) {
$r = new ReflectionMethod($callable[0], $callable[1]);
} elseif (is_object($callable) && !$callable instanceof Closure) {
$r = new ReflectionObject($callable);
$r = $r->getMethod('__invoke');
} else {
$r = new ReflectionFunction($callable);
}
$definition = $r->getParameters();
if ($this->hasNode('node')) {
array_shift($definition);
}
if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
array_shift($definition);
}
if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
array_shift($definition);
}
if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
foreach ($this->getAttribute('arguments') as $argument) {
array_shift($definition);
}
}
$arguments = array();
$pos = 0;
foreach ($definition as $param) {
$name = $this->normalizeName($param->name);
if (array_key_exists($name, $parameters)) {
if (array_key_exists($pos, $parameters)) {
throw new Twig_Error_Syntax(sprintf('Arguments "%s" is defined twice for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
}
$arguments[] = $parameters[$name];
unset($parameters[$name]);
} elseif (array_key_exists($pos, $parameters)) {
$arguments[] = $parameters[$pos];
unset($parameters[$pos]);
++$pos;
} elseif ($param->isDefaultValueAvailable()) {
$arguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1);
} elseif ($param->isOptional()) {
break;
} else {
throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
}
}
foreach (array_keys($parameters) as $name) {
throw new Twig_Error_Syntax(sprintf('Unknown argument "%s" for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
}
return $arguments;
}
protected function normalizeName($name)
{
return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name));
}
}

View file

@ -12,8 +12,7 @@
/**
* Represents an extension call node.
*
* @package twig
* @author Fabien Potencier <fabien@symfony.com>
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression
{

View file

@ -9,7 +9,7 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Filter extends Twig_Node_Expression
class Twig_Node_Expression_Filter extends Twig_Node_Expression_Call
{
public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
{
@ -19,54 +19,18 @@ class Twig_Node_Expression_Filter extends Twig_Node_Expression
public function compile(Twig_Compiler $compiler)
{
$name = $this->getNode('filter')->getAttribute('value');
if (false === $filter = $compiler->getEnvironment()->getFilter($name)) {
throw new Twig_Error_Syntax(sprintf('The filter "%s" does not exist', $name), $this->getLine());
$filter = $compiler->getEnvironment()->getFilter($name);
$this->setAttribute('name', $name);
$this->setAttribute('type', 'filter');
$this->setAttribute('thing', $filter);
$this->setAttribute('needs_environment', $filter->needsEnvironment());
$this->setAttribute('needs_context', $filter->needsContext());
$this->setAttribute('arguments', $filter->getArguments());
if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) {
$this->setAttribute('callable', $filter->getCallable());
}
$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);
}
}
protected function compileFilter(Twig_Compiler $compiler, Twig_FilterInterface $filter)
{
$compiler
->raw($filter->compile().'(')
->raw($filter->needsEnvironment() ? '$this->env, ' : '')
->raw($filter->needsContext() ? '$context, ' : '')
->subcompile($this->getNode('node'))
;
foreach ($this->getNode('arguments') as $node) {
$compiler
->raw(', ')
->subcompile($node)
;
}
$compiler->raw(')');
$this->compileCallable($compiler);
}
}

View file

@ -0,0 +1,43 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Returns the value or the default value when it is undefined or empty.
*
* <pre>
* {{ var.foo|default('foo item on var is not defined') }}
* </pre>
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter
{
public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
{
$default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getLine()), $arguments, $node->getLine());
if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) {
$test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine());
$false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine());
$node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine());
} else {
$node = $default;
}
parent::__construct($node, $filterName, $arguments, $lineno, $tag);
}
public function compile(Twig_Compiler $compiler)
{
$compiler->subcompile($this->getNode('node'));
}
}

View file

@ -8,7 +8,7 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Function extends Twig_Node_Expression
class Twig_Node_Expression_Function extends Twig_Node_Expression_Call
{
public function __construct($name, Twig_NodeInterface $arguments, $lineno)
{
@ -17,33 +17,19 @@ class Twig_Node_Expression_Function extends Twig_Node_Expression
public function compile(Twig_Compiler $compiler)
{
$function = $compiler->getEnvironment()->getFunction($this->getAttribute('name'));
if (false === $function) {
throw new Twig_Error_Syntax(sprintf('The function "%s" does not exist', $this->getAttribute('name')), $this->getLine());
$name = $this->getAttribute('name');
$function = $compiler->getEnvironment()->getFunction($name);
$this->setAttribute('name', $name);
$this->setAttribute('type', 'function');
$this->setAttribute('thing', $function);
$this->setAttribute('needs_environment', $function->needsEnvironment());
$this->setAttribute('needs_context', $function->needsContext());
$this->setAttribute('arguments', $function->getArguments());
if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) {
$this->setAttribute('callable', $function->getCallable());
}
$compiler
->raw($function->compile().'(')
->raw($function->needsEnvironment() ? '$this->env' : '')
;
if ($function->needsContext()) {
$compiler->raw($function->needsEnvironment() ? ', $context' : '$context');
}
$first = true;
foreach ($this->getNode('arguments') as $node) {
if (!$first) {
$compiler->raw(', ');
} else {
if ($function->needsEnvironment() || $function->needsContext()) {
$compiler->raw(', ');
}
$first = false;
}
$compiler->subcompile($node);
}
$compiler->raw(')');
$this->compileCallable($compiler);
}
}

View file

@ -11,43 +11,43 @@
*/
class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
{
public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_NodeInterface $arguments, $type, $lineno)
public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression_Array $arguments, $type, $lineno)
{
parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type), $lineno);
parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno);
}
public function compile(Twig_Compiler $compiler)
{
$compiler->raw('$this->getAttribute(');
if ($this->hasAttribute('is_defined_test') && $compiler->getEnvironment()->isStrictVariables()) {
$compiler->subcompile(new Twig_Node_Expression_Filter(
$this->getNode('node'),
new Twig_Node_Expression_Constant('default', $this->getLine()),
new Twig_Node(),
$this->getLine()
));
if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) {
$compiler->raw('twig_template_get_attributes($this, ');
} else {
$compiler->subcompile($this->getNode('node'));
$compiler->raw('$this->getAttribute(');
}
$compiler
->raw(', ')
->subcompile($this->getNode('attribute'))
->raw(', array(')
;
foreach ($this->getNode('arguments') as $node) {
$compiler
->subcompile($node)
->raw(', ')
;
if ($this->getAttribute('ignore_strict_check')) {
$this->getNode('node')->setAttribute('ignore_strict_check', true);
}
$compiler
->raw('), ')
->repr($this->getAttribute('type'))
->raw($this->hasAttribute('is_defined_test') ? ', true' : ', false')
->raw(')');
$compiler->subcompile($this->getNode('node'));
$compiler->raw(', ')->subcompile($this->getNode('attribute'));
if (count($this->getNode('arguments')) || Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
$compiler->raw(', ')->subcompile($this->getNode('arguments'));
if (Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
$compiler->raw(', ')->repr($this->getAttribute('type'));
}
if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
$compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false'));
}
if ($this->getAttribute('ignore_strict_check')) {
$compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false'));
}
}
$compiler->raw(')');
}
}

View file

@ -0,0 +1,41 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2012 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_MethodCall extends Twig_Node_Expression
{
public function __construct(Twig_Node_Expression $node, $method, Twig_Node_Expression_Array $arguments, $lineno)
{
parent::__construct(array('node' => $node, 'arguments' => $arguments), array('method' => $method, 'safe' => false), $lineno);
if ($node instanceof Twig_Node_Expression_Name) {
$node->setAttribute('always_defined', true);
}
}
public function compile(Twig_Compiler $compiler)
{
$compiler
->subcompile($this->getNode('node'))
->raw('->')
->raw($this->getAttribute('method'))
->raw('(')
;
$first = true;
foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) {
if (!$first) {
$compiler->raw(', ');
}
$first = false;
$compiler->subcompile($pair['value']);
}
$compiler->raw(')');
}
}

View file

@ -11,31 +11,78 @@
*/
class Twig_Node_Expression_Name extends Twig_Node_Expression
{
protected $specialVars = array(
'_self' => '$this',
'_context' => '$context',
'_charset' => '$this->env->getCharset()',
);
public function __construct($name, $lineno)
{
parent::__construct(array(), array('name' => $name), $lineno);
parent::__construct(array(), array('name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false), $lineno);
}
public function compile(Twig_Compiler $compiler)
{
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])) {
if ($this->getAttribute('is_defined_test')) {
if ($this->isSpecial()) {
$compiler->repr(true);
} else {
$compiler->raw('array_key_exists(')->repr($name)->raw(', $context)');
}
} elseif (isset($specialVars[$name])) {
$compiler->raw($specialVars[$name]);
} elseif ($this->isSpecial()) {
$compiler->raw($this->specialVars[$name]);
} elseif ($this->getAttribute('always_defined')) {
$compiler
->raw('$context[')
->string($name)
->raw(']')
;
} else {
$compiler->raw(sprintf('$this->getContext($context, \'%s\')', $name));
// remove the non-PHP 5.4 version when PHP 5.3 support is dropped
// as the non-optimized version is just a workaround for slow ternary operator
// when the context has a lot of variables
if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
// PHP 5.4 ternary operator performance was optimized
$compiler
->raw('(isset($context[')
->string($name)
->raw(']) ? $context[')
->string($name)
->raw('] : ')
;
if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) {
$compiler->raw('null)');
} else {
$compiler->raw('$this->getContext($context, ')->string($name)->raw('))');
}
} else {
$compiler
->raw('$this->getContext($context, ')
->string($name)
;
if ($this->getAttribute('ignore_strict_check')) {
$compiler->raw(', true');
}
$compiler
->raw(')')
;
}
}
}
public function isSpecial()
{
return isset($this->specialVars[$this->getAttribute('name')]);
}
public function isSimple()
{
return !$this->isSpecial() && !$this->getAttribute('is_defined_test');
}
}

View file

@ -13,14 +13,13 @@
/**
* Represents a parent node.
*
* @package twig
* @author Fabien Potencier <fabien@symfony.com>
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Expression_Parent extends Twig_Node_Expression
{
public function __construct($name, $lineno, $tag = null)
{
parent::__construct(array(), array('name' => $name), $lineno, $tag);
parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag);
}
/**
@ -30,10 +29,19 @@ class Twig_Node_Expression_Parent extends Twig_Node_Expression
*/
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw("\$this->renderParentBlock(")
->string($this->getAttribute('name'))
->raw(", \$context, \$blocks)")
;
if ($this->getAttribute('output')) {
$compiler
->addDebugInfo($this)
->write("\$this->displayParentBlock(")
->string($this->getAttribute('name'))
->raw(", \$context, \$blocks);\n")
;
} else {
$compiler
->raw("\$this->renderParentBlock(")
->string($this->getAttribute('name'))
->raw(", \$context, \$blocks)")
;
}
}
}

View file

@ -0,0 +1,26 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_TempName extends Twig_Node_Expression
{
public function __construct($name, $lineno)
{
parent::__construct(array(), array('name' => $name), $lineno);
}
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('$_')
->raw($this->getAttribute('name'))
->raw('_')
;
}
}

View file

@ -8,7 +8,7 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Test extends Twig_Node_Expression
class Twig_Node_Expression_Test extends Twig_Node_Expression_Call
{
public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
{
@ -17,44 +17,16 @@ class Twig_Node_Expression_Test extends Twig_Node_Expression
public function compile(Twig_Compiler $compiler)
{
$testMap = $compiler->getEnvironment()->getTests();
if (!isset($testMap[$this->getAttribute('name')])) {
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');
$test = $compiler->getEnvironment()->getTest($name);
// 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());
}
return;
$this->setAttribute('name', $name);
$this->setAttribute('type', 'test');
$this->setAttribute('thing', $test);
if ($test instanceof Twig_TestCallableInterface || $test instanceof Twig_SimpleTest) {
$this->setAttribute('callable', $test->getCallable());
}
$compiler
->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 => $arg) {
$compiler->subcompile($arg);
if ($i != $max) {
$compiler->raw(', ');
}
}
}
$compiler->raw(')');
$this->compileCallable($compiler);
}
}

View file

@ -0,0 +1,46 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Checks if a variable is the exact same value as a constant.
*
* <pre>
* {% if post.status is constant('Post::PUBLISHED') %}
* the status attribute is exactly the same as Post::PUBLISHED
* {% endif %}
* </pre>
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test
{
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('node'))
->raw(' === constant(')
;
if ($this->getNode('arguments')->hasNode(1)) {
$compiler
->raw('get_class(')
->subcompile($this->getNode('arguments')->getNode(1))
->raw(')."::".')
;
}
$compiler
->subcompile($this->getNode('arguments')->getNode(0))
->raw('))')
;
}
}

View file

@ -0,0 +1,54 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Checks if a variable is defined in the current context.
*
* <pre>
* {# defined works with variable names and variable attributes #}
* {% if foo is defined %}
* {# ... #}
* {% endif %}
* </pre>
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test
{
public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
{
parent::__construct($node, $name, $arguments, $lineno);
if ($node instanceof Twig_Node_Expression_Name) {
$node->setAttribute('is_defined_test', true);
} elseif ($node instanceof Twig_Node_Expression_GetAttr) {
$node->setAttribute('is_defined_test', true);
$this->changeIgnoreStrictCheck($node);
} else {
throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine());
}
}
protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node)
{
$node->setAttribute('ignore_strict_check', true);
if ($node->getNode('node') instanceof Twig_Node_Expression_GetAttr) {
$this->changeIgnoreStrictCheck($node->getNode('node'));
}
}
public function compile(Twig_Compiler $compiler)
{
$compiler->subcompile($this->getNode('node'));
}
}

View file

@ -0,0 +1,33 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Checks if a variable is divisible by a number.
*
* <pre>
* {% if loop.index is divisibleby(3) %}
* </pre>
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test
{
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('(0 == ')
->subcompile($this->getNode('node'))
->raw(' % ')
->subcompile($this->getNode('arguments')->getNode(0))
->raw(')')
;
}
}

View file

@ -0,0 +1,32 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Checks if a number is even.
*
* <pre>
* {{ var is even }}
* </pre>
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test
{
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('node'))
->raw(' % 2 == 0')
->raw(')')
;
}
}

View file

@ -0,0 +1,31 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Checks that a variable is null.
*
* <pre>
* {{ var is none }}
* </pre>
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test
{
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('(null === ')
->subcompile($this->getNode('node'))
->raw(')')
;
}
}

View file

@ -0,0 +1,32 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Checks if a number is odd.
*
* <pre>
* {{ var is odd }}
* </pre>
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test
{
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('node'))
->raw(' % 2 == 1')
->raw(')')
;
}
}

View file

@ -0,0 +1,29 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Checks if a variable is the same as another one (=== in PHP).
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test
{
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('node'))
->raw(' === ')
->subcompile($this->getNode('arguments')->getNode(0))
->raw(')')
;
}
}