summaryrefslogtreecommitdiff
path: root/inc/lib/Twig/Node
diff options
context:
space:
mode:
authorMichael Foster <savetheinternet@tinyboard.org>2013-08-01 15:20:12 -0400
committerMichael Foster <savetheinternet@tinyboard.org>2013-08-01 15:20:12 -0400
commit0fe552857468aa12097a74e08f51f5aaa983be07 (patch)
tree22dbca1be90d7086b20a077752552296abf23325 /inc/lib/Twig/Node
parent22f3a95e0e421de05a11633eac846df96a2a4768 (diff)
Upgrade Twig library
Diffstat (limited to 'inc/lib/Twig/Node')
-rw-r--r--inc/lib/Twig/Node/AutoEscape.php3
-rw-r--r--inc/lib/Twig/Node/Block.php3
-rw-r--r--inc/lib/Twig/Node/BlockReference.php3
-rw-r--r--inc/lib/Twig/Node/Body.php19
-rw-r--r--inc/lib/Twig/Node/Do.php38
-rw-r--r--inc/lib/Twig/Node/Embed.php38
-rw-r--r--inc/lib/Twig/Node/Expression.php3
-rw-r--r--inc/lib/Twig/Node/Expression/Array.php51
-rw-r--r--inc/lib/Twig/Node/Expression/AssignName.php6
-rw-r--r--inc/lib/Twig/Node/Expression/Binary/FloorDiv.php4
-rw-r--r--inc/lib/Twig/Node/Expression/BlockReference.php3
-rw-r--r--inc/lib/Twig/Node/Expression/Call.php178
-rw-r--r--inc/lib/Twig/Node/Expression/ExtensionReference.php3
-rw-r--r--inc/lib/Twig/Node/Expression/Filter.php58
-rw-r--r--inc/lib/Twig/Node/Expression/Filter/Default.php43
-rw-r--r--inc/lib/Twig/Node/Expression/Function.php38
-rw-r--r--inc/lib/Twig/Node/Expression/GetAttr.php54
-rw-r--r--inc/lib/Twig/Node/Expression/MethodCall.php41
-rw-r--r--inc/lib/Twig/Node/Expression/Name.php71
-rw-r--r--inc/lib/Twig/Node/Expression/Parent.php24
-rw-r--r--inc/lib/Twig/Node/Expression/TempName.php26
-rw-r--r--inc/lib/Twig/Node/Expression/Test.php44
-rw-r--r--inc/lib/Twig/Node/Expression/Test/Constant.php46
-rw-r--r--inc/lib/Twig/Node/Expression/Test/Defined.php54
-rw-r--r--inc/lib/Twig/Node/Expression/Test/Divisibleby.php33
-rw-r--r--inc/lib/Twig/Node/Expression/Test/Even.php32
-rw-r--r--inc/lib/Twig/Node/Expression/Test/Null.php31
-rw-r--r--inc/lib/Twig/Node/Expression/Test/Odd.php32
-rw-r--r--inc/lib/Twig/Node/Expression/Test/Sameas.php29
-rw-r--r--inc/lib/Twig/Node/Flush.php36
-rw-r--r--inc/lib/Twig/Node/For.php63
-rw-r--r--inc/lib/Twig/Node/ForLoop.php55
-rw-r--r--inc/lib/Twig/Node/If.php3
-rw-r--r--inc/lib/Twig/Node/Import.php3
-rw-r--r--inc/lib/Twig/Node/Include.php45
-rw-r--r--inc/lib/Twig/Node/Macro.php59
-rw-r--r--inc/lib/Twig/Node/Module.php127
-rw-r--r--inc/lib/Twig/Node/Print.php3
-rw-r--r--inc/lib/Twig/Node/Sandbox.php3
-rw-r--r--inc/lib/Twig/Node/SandboxedModule.php23
-rw-r--r--inc/lib/Twig/Node/SandboxedPrint.php3
-rw-r--r--inc/lib/Twig/Node/Set.php9
-rw-r--r--inc/lib/Twig/Node/SetTemp.php35
-rw-r--r--inc/lib/Twig/Node/Spaceless.php3
-rw-r--r--inc/lib/Twig/Node/Text.php3
45 files changed, 1161 insertions, 320 deletions
diff --git a/inc/lib/Twig/Node/AutoEscape.php b/inc/lib/Twig/Node/AutoEscape.php
index a0c2ee6d..8f190e0b 100644
--- a/inc/lib/Twig/Node/AutoEscape.php
+++ b/inc/lib/Twig/Node/AutoEscape.php
@@ -18,8 +18,7 @@
*
* If autoescaping is disabled, then the value is false.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_AutoEscape extends Twig_Node
{
diff --git a/inc/lib/Twig/Node/Block.php b/inc/lib/Twig/Node/Block.php
index 5548ad06..50eb67ed 100644
--- a/inc/lib/Twig/Node/Block.php
+++ b/inc/lib/Twig/Node/Block.php
@@ -13,8 +13,7 @@
/**
* Represents a block node.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Block extends Twig_Node
{
diff --git a/inc/lib/Twig/Node/BlockReference.php b/inc/lib/Twig/Node/BlockReference.php
index 53f6287c..013e369e 100644
--- a/inc/lib/Twig/Node/BlockReference.php
+++ b/inc/lib/Twig/Node/BlockReference.php
@@ -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_BlockReference extends Twig_Node implements Twig_NodeOutputInterface
{
diff --git a/inc/lib/Twig/Node/Body.php b/inc/lib/Twig/Node/Body.php
new file mode 100644
index 00000000..3ffb1342
--- /dev/null
+++ b/inc/lib/Twig/Node/Body.php
@@ -0,0 +1,19 @@
+<?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.
+ */
+
+/**
+ * Represents a body node.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class Twig_Node_Body extends Twig_Node
+{
+}
diff --git a/inc/lib/Twig/Node/Do.php b/inc/lib/Twig/Node/Do.php
new file mode 100644
index 00000000..c528066b
--- /dev/null
+++ b/inc/lib/Twig/Node/Do.php
@@ -0,0 +1,38 @@
+<?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.
+ */
+
+/**
+ * Represents a do node.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class Twig_Node_Do extends Twig_Node
+{
+ public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
+ {
+ parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
+ }
+
+ /**
+ * Compiles the node to PHP.
+ *
+ * @param Twig_Compiler A Twig_Compiler instance
+ */
+ public function compile(Twig_Compiler $compiler)
+ {
+ $compiler
+ ->addDebugInfo($this)
+ ->write('')
+ ->subcompile($this->getNode('expr'))
+ ->raw(";\n")
+ ;
+ }
+}
diff --git a/inc/lib/Twig/Node/Embed.php b/inc/lib/Twig/Node/Embed.php
new file mode 100644
index 00000000..4c9456dc
--- /dev/null
+++ b/inc/lib/Twig/Node/Embed.php
@@ -0,0 +1,38 @@
+<?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.
+ */
+
+/**
+ * Represents an embed node.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class Twig_Node_Embed extends Twig_Node_Include
+{
+ // we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module)
+ public function __construct($filename, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
+ {
+ parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
+
+ $this->setAttribute('filename', $filename);
+ $this->setAttribute('index', $index);
+ }
+
+ protected function addGetTemplate(Twig_Compiler $compiler)
+ {
+ $compiler
+ ->write("\$this->env->loadTemplate(")
+ ->string($this->getAttribute('filename'))
+ ->raw(', ')
+ ->string($this->getAttribute('index'))
+ ->raw(")")
+ ;
+ }
+}
diff --git a/inc/lib/Twig/Node/Expression.php b/inc/lib/Twig/Node/Expression.php
index 13b170e5..a7382e7d 100644
--- a/inc/lib/Twig/Node/Expression.php
+++ b/inc/lib/Twig/Node/Expression.php
@@ -13,8 +13,7 @@
/**
* Abstract class for all nodes that represents an expression.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
abstract class Twig_Node_Expression extends Twig_Node
{
diff --git a/inc/lib/Twig/Node/Expression/Array.php b/inc/lib/Twig/Node/Expression/Array.php
index 2d860823..1da785fe 100644
--- a/inc/lib/Twig/Node/Expression/Array.php
+++ b/inc/lib/Twig/Node/Expression/Array.php
@@ -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(')');
diff --git a/inc/lib/Twig/Node/Expression/AssignName.php b/inc/lib/Twig/Node/Expression/AssignName.php
index 67f12509..2ddea78c 100644
--- a/inc/lib/Twig/Node/Expression/AssignName.php
+++ b/inc/lib/Twig/Node/Expression/AssignName.php
@@ -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(']')
+ ;
}
}
diff --git a/inc/lib/Twig/Node/Expression/Binary/FloorDiv.php b/inc/lib/Twig/Node/Expression/Binary/FloorDiv.php
index e86b1ea0..7fbd0556 100644
--- a/inc/lib/Twig/Node/Expression/Binary/FloorDiv.php
+++ b/inc/lib/Twig/Node/Expression/Binary/FloorDiv.php
@@ -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)
diff --git a/inc/lib/Twig/Node/Expression/BlockReference.php b/inc/lib/Twig/Node/Expression/BlockReference.php
index 174d9097..647196eb 100644
--- a/inc/lib/Twig/Node/Expression/BlockReference.php
+++ b/inc/lib/Twig/Node/Expression/BlockReference.php
@@ -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
{
diff --git a/inc/lib/Twig/Node/Expression/Call.php b/inc/lib/Twig/Node/Expression/Call.php
new file mode 100644
index 00000000..87b62deb
--- /dev/null
+++ b/inc/lib/Twig/Node/Expression/Call.php
@@ -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));
+ }
+}
diff --git a/inc/lib/Twig/Node/Expression/ExtensionReference.php b/inc/lib/Twig/Node/Expression/ExtensionReference.php
index cb4efad0..00ac6701 100644
--- a/inc/lib/Twig/Node/Expression/ExtensionReference.php
+++ b/inc/lib/Twig/Node/Expression/ExtensionReference.php
@@ -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
{
diff --git a/inc/lib/Twig/Node/Expression/Filter.php b/inc/lib/Twig/Node/Expression/Filter.php
index 101e6df0..207b062a 100644
--- a/inc/lib/Twig/Node/Expression/Filter.php
+++ b/inc/lib/Twig/Node/Expression/Filter.php
@@ -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());
- }
-
- $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'))
- ;
+ $filter = $compiler->getEnvironment()->getFilter($name);
- foreach ($this->getNode('arguments') as $node) {
- $compiler
- ->raw(', ')
- ->subcompile($node)
- ;
+ $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());
}
- $compiler->raw(')');
+ $this->compileCallable($compiler);
}
}
diff --git a/inc/lib/Twig/Node/Expression/Filter/Default.php b/inc/lib/Twig/Node/Expression/Filter/Default.php
new file mode 100644
index 00000000..1827c888
--- /dev/null
+++ b/inc/lib/Twig/Node/Expression/Filter/Default.php
@@ -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'));
+ }
+}
diff --git a/inc/lib/Twig/Node/Expression/Function.php b/inc/lib/Twig/Node/Expression/Function.php
index 3f457199..3e1f6b55 100644
--- a/inc/lib/Twig/Node/Expression/Function.php
+++ b/inc/lib/Twig/Node/Expression/Function.php
@@ -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());
- }
-
- $compiler
- ->raw($function->compile().'(')
- ->raw($function->needsEnvironment() ? '$this->env' : '')
- ;
-
- if ($function->needsContext()) {
- $compiler->raw($function->needsEnvironment() ? ', $context' : '$context');
- }
+ $name = $this->getAttribute('name');
+ $function = $compiler->getEnvironment()->getFunction($name);
- $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);
+ $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(')');
+ $this->compileCallable($compiler);
}
}
diff --git a/inc/lib/Twig/Node/Expression/GetAttr.php b/inc/lib/Twig/Node/Expression/GetAttr.php
index eb9e6050..81a9b137 100644
--- a/inc/lib/Twig/Node/Expression/GetAttr.php
+++ b/inc/lib/Twig/Node/Expression/GetAttr.php
@@ -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(');
+ }
+
+ if ($this->getAttribute('ignore_strict_check')) {
+ $this->getNode('node')->setAttribute('ignore_strict_check', true);
}
- $compiler
- ->raw(', ')
- ->subcompile($this->getNode('attribute'))
- ->raw(', array(')
- ;
+ $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'));
+ }
- foreach ($this->getNode('arguments') as $node) {
- $compiler
- ->subcompile($node)
- ->raw(', ')
- ;
+ if ($this->getAttribute('ignore_strict_check')) {
+ $compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false'));
+ }
}
- $compiler
- ->raw('), ')
- ->repr($this->getAttribute('type'))
- ->raw($this->hasAttribute('is_defined_test') ? ', true' : ', false')
- ->raw(')');
+ $compiler->raw(')');
}
}
diff --git a/inc/lib/Twig/Node/Expression/MethodCall.php b/inc/lib/Twig/Node/Expression/MethodCall.php
new file mode 100644
index 00000000..620b02bf
--- /dev/null
+++ b/inc/lib/Twig/Node/Expression/MethodCall.php
@@ -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(')');
+ }
+}
diff --git a/inc/lib/Twig/Node/Expression/Name.php b/inc/lib/Twig/Node/Expression/Name.php
index fceda2b7..3b8fae01 100644
--- a/inc/lib/Twig/Node/Expression/Name.php
+++ b/inc/lib/Twig/Node/Expression/Name.php
@@ -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');
+ }
}
diff --git a/inc/lib/Twig/Node/Expression/Parent.php b/inc/lib/Twig/Node/Expression/Parent.php
index 5689fe45..dcf618c0 100644
--- a/inc/lib/Twig/Node/Expression/Parent.php
+++ b/inc/lib/Twig/Node/Expression/Parent.php
@@ -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)")
+ ;
+ }
}
}
diff --git a/inc/lib/Twig/Node/Expression/TempName.php b/inc/lib/Twig/Node/Expression/TempName.php
new file mode 100644
index 00000000..e6b058e8
--- /dev/null
+++ b/inc/lib/Twig/Node/Expression/TempName.php
@@ -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('_')
+ ;
+ }
+}
diff --git a/inc/lib/Twig/Node/Expression/Test.php b/inc/lib/Twig/Node/Expression/Test.php
index ef35df6b..639f501a 100644
--- a/inc/lib/Twig/Node/Expression/Test.php
+++ b/inc/lib/Twig/Node/Expression/Test.php
@@ -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');
-
- // 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;
- }
-
- $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);
+ $test = $compiler->getEnvironment()->getTest($name);
- if ($i != $max) {
- $compiler->raw(', ');
- }
- }
+ $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(')');
+ $this->compileCallable($compiler);
}
}
diff --git a/inc/lib/Twig/Node/Expression/Test/Constant.php b/inc/lib/Twig/Node/Expression/Test/Constant.php
new file mode 100644
index 00000000..de55f5f5
--- /dev/null
+++ b/inc/lib/Twig/Node/Expression/Test/Constant.php
@@ -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('))')
+ ;
+ }
+}
diff --git a/inc/lib/Twig/Node/Expression/Test/Defined.php b/inc/lib/Twig/Node/Expression/Test/Defined.php
new file mode 100644
index 00000000..247b2e23
--- /dev/null
+++ b/inc/lib/Twig/Node/Expression/Test/Defined.php
@@ -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'));
+ }
+}
diff --git a/inc/lib/Twig/Node/Expression/Test/Divisibleby.php b/inc/lib/Twig/Node/Expression/Test/Divisibleby.php
new file mode 100644
index 00000000..0aceb530
--- /dev/null
+++ b/inc/lib/Twig/Node/Expression/Test/Divisibleby.php
@@ -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(')')
+ ;
+ }
+}
diff --git a/inc/lib/Twig/Node/Expression/Test/Even.php b/inc/lib/Twig/Node/Expression/Test/Even.php
new file mode 100644
index 00000000..d7853e89
--- /dev/null
+++ b/inc/lib/Twig/Node/Expression/Test/Even.php
@@ -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(')')
+ ;
+ }
+}
diff --git a/inc/lib/Twig/Node/Expression/Test/Null.php b/inc/lib/Twig/Node/Expression/Test/Null.php
new file mode 100644
index 00000000..1c83825a
--- /dev/null
+++ b/inc/lib/Twig/Node/Expression/Test/Null.php
@@ -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(')')
+ ;
+ }
+}
diff --git a/inc/lib/Twig/Node/Expression/Test/Odd.php b/inc/lib/Twig/Node/Expression/Test/Odd.php
new file mode 100644
index 00000000..421c19e8
--- /dev/null
+++ b/inc/lib/Twig/Node/Expression/Test/Odd.php
@@ -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(')')
+ ;
+ }
+}
diff --git a/inc/lib/Twig/Node/Expression/Test/Sameas.php b/inc/lib/Twig/Node/Expression/Test/Sameas.php
new file mode 100644
index 00000000..b48905ee
--- /dev/null
+++ b/inc/lib/Twig/Node/Expression/Test/Sameas.php
@@ -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(')')
+ ;
+ }
+}
diff --git a/inc/lib/Twig/Node/Flush.php b/inc/lib/Twig/Node/Flush.php
new file mode 100644
index 00000000..0467ddce
--- /dev/null
+++ b/inc/lib/Twig/Node/Flush.php
@@ -0,0 +1,36 @@
+<?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.
+ */
+
+/**
+ * Represents a flush node.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class Twig_Node_Flush extends Twig_Node
+{
+ public function __construct($lineno, $tag)
+ {
+ parent::__construct(array(), array(), $lineno, $tag);
+ }
+
+ /**
+ * Compiles the node to PHP.
+ *
+ * @param Twig_Compiler A Twig_Compiler instance
+ */
+ public function compile(Twig_Compiler $compiler)
+ {
+ $compiler
+ ->addDebugInfo($this)
+ ->write("flush();\n")
+ ;
+ }
+}
diff --git a/inc/lib/Twig/Node/For.php b/inc/lib/Twig/Node/For.php
index eb204e28..d1ff371d 100644
--- a/inc/lib/Twig/Node/For.php
+++ b/inc/lib/Twig/Node/For.php
@@ -13,14 +13,21 @@
/**
* Represents a for node.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_For extends Twig_Node
{
+ protected $loop;
+
public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_Node_Expression $ifexpr = null, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null)
{
- parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'ifexpr' => $ifexpr, 'body' => $body, 'else' => $else), array('with_loop' => true), $lineno, $tag);
+ $body = new Twig_Node(array($body, $this->loop = new Twig_Node_ForLoop($lineno, $tag)));
+
+ if (null !== $ifexpr) {
+ $body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag);
+ }
+
+ parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body, 'else' => $else), array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag);
}
/**
@@ -53,7 +60,7 @@ class Twig_Node_For extends Twig_Node
->write(");\n")
;
- if (null === $this->getNode('ifexpr')) {
+ if (!$this->getAttribute('ifexpr')) {
$compiler
->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n")
->indent()
@@ -68,6 +75,10 @@ class Twig_Node_For extends Twig_Node
}
}
+ $this->loop->setAttribute('else', null !== $this->getNode('else'));
+ $this->loop->setAttribute('with_loop', $this->getAttribute('with_loop'));
+ $this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr'));
+
$compiler
->write("foreach (\$context['_seq'] as ")
->subcompile($this->getNode('key_target'))
@@ -75,47 +86,7 @@ class Twig_Node_For extends Twig_Node
->subcompile($this->getNode('value_target'))
->raw(") {\n")
->indent()
- ;
-
- if (null !== $this->getNode('ifexpr')) {
- $compiler
- ->write("if (!(")
- ->subcompile($this->getNode('ifexpr'))
- ->raw(")) {\n")
- ->indent()
- ->write("continue;\n")
- ->outdent()
- ->write("}\n\n")
- ;
- }
-
- $compiler->subcompile($this->getNode('body'));
-
- if (null !== $this->getNode('else')) {
- $compiler->write("\$context['_iterated'] = true;\n");
- }
-
- if ($this->getAttribute('with_loop')) {
- $compiler
- ->write("++\$context['loop']['index0'];\n")
- ->write("++\$context['loop']['index'];\n")
- ->write("\$context['loop']['first'] = false;\n")
- ;
-
- if (null === $this->getNode('ifexpr')) {
- $compiler
- ->write("if (isset(\$context['loop']['length'])) {\n")
- ->indent()
- ->write("--\$context['loop']['revindex0'];\n")
- ->write("--\$context['loop']['revindex'];\n")
- ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
- ->outdent()
- ->write("}\n")
- ;
- }
- }
-
- $compiler
+ ->subcompile($this->getNode('body'))
->outdent()
->write("}\n")
;
@@ -136,6 +107,6 @@ class Twig_Node_For extends Twig_Node
$compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n");
// keep the values set in the inner context for variables defined in the outer context
- $compiler->write("\$context = array_merge(\$_parent, array_intersect_key(\$context, \$_parent));\n");
+ $compiler->write("\$context = array_intersect_key(\$context, \$_parent) + \$_parent;\n");
}
}
diff --git a/inc/lib/Twig/Node/ForLoop.php b/inc/lib/Twig/Node/ForLoop.php
new file mode 100644
index 00000000..b8841583
--- /dev/null
+++ b/inc/lib/Twig/Node/ForLoop.php
@@ -0,0 +1,55 @@
+<?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.
+ */
+
+/**
+ * Internal node used by the for node.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class Twig_Node_ForLoop extends Twig_Node
+{
+ public function __construct($lineno, $tag = null)
+ {
+ parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag);
+ }
+
+ /**
+ * Compiles the node to PHP.
+ *
+ * @param Twig_Compiler A Twig_Compiler instance
+ */
+ public function compile(Twig_Compiler $compiler)
+ {
+ if ($this->getAttribute('else')) {
+ $compiler->write("\$context['_iterated'] = true;\n");
+ }
+
+ if ($this->getAttribute('with_loop')) {
+ $compiler
+ ->write("++\$context['loop']['index0'];\n")
+ ->write("++\$context['loop']['index'];\n")
+ ->write("\$context['loop']['first'] = false;\n")
+ ;
+
+ if (!$this->getAttribute('ifexpr')) {
+ $compiler
+ ->write("if (isset(\$context['loop']['length'])) {\n")
+ ->indent()
+ ->write("--\$context['loop']['revindex0'];\n")
+ ->write("--\$context['loop']['revindex'];\n")
+ ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
+ ->outdent()
+ ->write("}\n")
+ ;
+ }
+ }
+ }
+}
diff --git a/inc/lib/Twig/Node/If.php b/inc/lib/Twig/Node/If.php
index aa12efbe..4296a8d6 100644
--- a/inc/lib/Twig/Node/If.php
+++ b/inc/lib/Twig/Node/If.php
@@ -13,8 +13,7 @@
/**
* Represents an if node.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_If extends Twig_Node
{
diff --git a/inc/lib/Twig/Node/Import.php b/inc/lib/Twig/Node/Import.php
index a327411d..99efc091 100644
--- a/inc/lib/Twig/Node/Import.php
+++ b/inc/lib/Twig/Node/Import.php
@@ -12,8 +12,7 @@
/**
* Represents an import node.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Import extends Twig_Node
{
diff --git a/inc/lib/Twig/Node/Include.php b/inc/lib/Twig/Node/Include.php
index 467749b5..ed4a3751 100644
--- a/inc/lib/Twig/Node/Include.php
+++ b/inc/lib/Twig/Node/Include.php
@@ -13,8 +13,7 @@
/**
* Represents an include node.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface
{
@@ -39,21 +38,46 @@ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface
;
}
+ $this->addGetTemplate($compiler);
+
+ $compiler->raw('->display(');
+
+ $this->addTemplateArguments($compiler);
+
+ $compiler->raw(");\n");
+
+ if ($this->getAttribute('ignore_missing')) {
+ $compiler
+ ->outdent()
+ ->write("} catch (Twig_Error_Loader \$e) {\n")
+ ->indent()
+ ->write("// ignore missing template\n")
+ ->outdent()
+ ->write("}\n\n")
+ ;
+ }
+ }
+
+ protected function addGetTemplate(Twig_Compiler $compiler)
+ {
if ($this->getNode('expr') instanceof Twig_Node_Expression_Constant) {
$compiler
->write("\$this->env->loadTemplate(")
->subcompile($this->getNode('expr'))
- ->raw(")->display(")
+ ->raw(")")
;
} else {
$compiler
->write("\$template = \$this->env->resolveTemplate(")
->subcompile($this->getNode('expr'))
->raw(");\n")
- ->write('$template->display(')
+ ->write('$template')
;
}
+ }
+ protected function addTemplateArguments(Twig_Compiler $compiler)
+ {
if (false === $this->getAttribute('only')) {
if (null === $this->getNode('variables')) {
$compiler->raw('$context');
@@ -71,18 +95,5 @@ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface
$compiler->subcompile($this->getNode('variables'));
}
}
-
- $compiler->raw(");\n");
-
- if ($this->getAttribute('ignore_missing')) {
- $compiler
- ->outdent()
- ->write("} catch (Twig_Error_Loader \$e) {\n")
- ->indent()
- ->write("// ignore missing template\n")
- ->outdent()
- ->write("}\n\n")
- ;
- }
}
}
diff --git a/inc/lib/Twig/Node/Macro.php b/inc/lib/Twig/Node/Macro.php
index 9f95570f..89910618 100644
--- a/inc/lib/Twig/Node/Macro.php
+++ b/inc/lib/Twig/Node/Macro.php
@@ -12,8 +12,7 @@
/**
* Represents a macro node.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Macro extends Twig_Node
{
@@ -29,43 +28,67 @@ class Twig_Node_Macro extends Twig_Node
*/
public function compile(Twig_Compiler $compiler)
{
- $arguments = array();
- foreach ($this->getNode('arguments') as $argument) {
- $arguments[] = '$'.$argument->getAttribute('name').' = null';
+ $compiler
+ ->addDebugInfo($this)
+ ->write(sprintf("public function get%s(", $this->getAttribute('name')))
+ ;
+
+ $count = count($this->getNode('arguments'));
+ $pos = 0;
+ foreach ($this->getNode('arguments') as $name => $default) {
+ $compiler
+ ->raw('$_'.$name.' = ')
+ ->subcompile($default)
+ ;
+
+ if (++$pos < $count) {
+ $compiler->raw(', ');
+ }
}
$compiler
- ->addDebugInfo($this)
- ->write(sprintf("public function get%s(%s)\n", $this->getAttribute('name'), implode(', ', $arguments)), "{\n")
- ->indent()
- ->write("\$context = array_merge(\$this->env->getGlobals(), array(\n")
+ ->raw(")\n")
+ ->write("{\n")
->indent()
;
- foreach ($this->getNode('arguments') as $argument) {
+ if (!count($this->getNode('arguments'))) {
+ $compiler->write("\$context = \$this->env->getGlobals();\n\n");
+ } else {
$compiler
- ->write('')
- ->string($argument->getAttribute('name'))
- ->raw(' => $'.$argument->getAttribute('name'))
- ->raw(",\n")
+ ->write("\$context = \$this->env->mergeGlobals(array(\n")
+ ->indent()
+ ;
+
+ foreach ($this->getNode('arguments') as $name => $default) {
+ $compiler
+ ->write('')
+ ->string($name)
+ ->raw(' => $_'.$name)
+ ->raw(",\n")
+ ;
+ }
+
+ $compiler
+ ->outdent()
+ ->write("));\n\n")
;
}
$compiler
- ->outdent()
- ->write("));\n\n")
+ ->write("\$blocks = array();\n\n")
->write("ob_start();\n")
->write("try {\n")
->indent()
->subcompile($this->getNode('body'))
->outdent()
- ->write("} catch(Exception \$e) {\n")
+ ->write("} catch (Exception \$e) {\n")
->indent()
->write("ob_end_clean();\n\n")
->write("throw \$e;\n")
->outdent()
->write("}\n\n")
- ->write("return ob_get_clean();\n")
+ ->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());\n")
->outdent()
->write("}\n\n")
;
diff --git a/inc/lib/Twig/Node/Module.php b/inc/lib/Twig/Node/Module.php
index 9b8c55e3..585048b8 100644
--- a/inc/lib/Twig/Node/Module.php
+++ b/inc/lib/Twig/Node/Module.php
@@ -13,14 +13,19 @@
/**
* Represents a module node.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Module extends Twig_Node
{
- public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $filename)
+ public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename)
{
- parent::__construct(array('parent' => $parent, 'body' => $body, 'blocks' => $blocks, 'macros' => $macros, 'traits' => $traits), array('filename' => $filename), 1);
+ // embedded templates are set as attributes so that they are only visited once by the visitors
+ parent::__construct(array('parent' => $parent, 'body' => $body, 'blocks' => $blocks, 'macros' => $macros, 'traits' => $traits), array('filename' => $filename, 'index' => null, 'embedded_templates' => $embeddedTemplates), 1);
+ }
+
+ public function setIndex($index)
+ {
+ $this->setAttribute('index', $index);
}
/**
@@ -31,13 +36,21 @@ class Twig_Node_Module extends Twig_Node
public function compile(Twig_Compiler $compiler)
{
$this->compileTemplate($compiler);
+
+ foreach ($this->getAttribute('embedded_templates') as $template) {
+ $compiler->subcompile($template);
+ }
}
protected function compileTemplate(Twig_Compiler $compiler)
{
+ if (!$this->getAttribute('index')) {
+ $compiler->write('<?php');
+ }
+
$this->compileClassHeader($compiler);
- if (count($this->getNode('blocks')) || count($this->getNode('traits'))) {
+ if (count($this->getNode('blocks')) || count($this->getNode('traits')) || null === $this->getNode('parent') || $this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
$this->compileConstructor($compiler);
}
@@ -57,29 +70,31 @@ class Twig_Node_Module extends Twig_Node
$this->compileIsTraitable($compiler);
+ $this->compileDebugInfo($compiler);
+
$this->compileClassFooter($compiler);
}
protected function compileGetParent(Twig_Compiler $compiler)
{
+ if (null === $this->getNode('parent')) {
+ return;
+ }
+
$compiler
->write("protected function doGetParent(array \$context)\n", "{\n")
->indent()
->write("return ")
;
- if (null === $this->getNode('parent')) {
- $compiler->raw("false");
+ if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
+ $compiler->subcompile($this->getNode('parent'));
} else {
- if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
- $compiler->subcompile($this->getNode('parent'));
- } else {
- $compiler
- ->raw("\$this->env->resolveTemplate(")
- ->subcompile($this->getNode('parent'))
- ->raw(")")
- ;
- }
+ $compiler
+ ->raw("\$this->env->resolveTemplate(")
+ ->subcompile($this->getNode('parent'))
+ ->raw(")")
+ ;
}
$compiler
@@ -91,21 +106,25 @@ class Twig_Node_Module extends Twig_Node
protected function compileDisplayBody(Twig_Compiler $compiler)
{
- $compiler->write("\$context = array_merge(\$this->env->getGlobals(), \$context);\n\n");
$compiler->subcompile($this->getNode('body'));
if (null !== $this->getNode('parent')) {
- $compiler->write("\$this->getParent(\$context)->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
+ if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
+ $compiler->write("\$this->parent");
+ } else {
+ $compiler->write("\$this->getParent(\$context)");
+ }
+ $compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
}
}
protected function compileClassHeader(Twig_Compiler $compiler)
{
$compiler
- ->write("<?php\n\n")
+ ->write("\n\n")
// if the filename contains */, add a blank to avoid a PHP parse error
->write("/* ".str_replace('*/', '* /', $this->getAttribute('filename'))." */\n")
- ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename')))
+ ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'), $this->getAttribute('index')))
->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass()))
->write("{\n")
->indent()
@@ -120,6 +139,17 @@ class Twig_Node_Module extends Twig_Node
->write("parent::__construct(\$env);\n\n")
;
+ // parent
+ if (null === $this->getNode('parent')) {
+ $compiler->write("\$this->parent = false;\n\n");
+ } elseif ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
+ $compiler
+ ->write("\$this->parent = \$this->env->loadTemplate(")
+ ->subcompile($this->getNode('parent'))
+ ->raw(");\n\n")
+ ;
+ }
+
$countTraits = count($this->getNode('traits'));
if ($countTraits) {
// traits
@@ -151,18 +181,32 @@ class Twig_Node_Module extends Twig_Node
}
}
- $compiler
- ->write("\$this->blocks = array_merge(\n")
- ->indent()
- ;
+ if ($countTraits > 1) {
+ $compiler
+ ->write("\$this->traits = array_merge(\n")
+ ->indent()
+ ;
+
+ for ($i = 0; $i < $countTraits; $i++) {
+ $compiler
+ ->write(sprintf("\$_trait_%s_blocks".($i == $countTraits - 1 ? '' : ',')."\n", $i))
+ ;
+ }
- for ($i = 0; $i < $countTraits; $i++) {
$compiler
- ->write(sprintf("\$_trait_%s_blocks,\n", $i))
+ ->outdent()
+ ->write(");\n\n")
+ ;
+ } else {
+ $compiler
+ ->write("\$this->traits = \$_trait_0_blocks;\n\n")
;
}
$compiler
+ ->write("\$this->blocks = array_merge(\n")
+ ->indent()
+ ->write("\$this->traits,\n")
->write("array(\n")
;
} else {
@@ -250,11 +294,21 @@ class Twig_Node_Module extends Twig_Node
// only contains blocks and use statements.
$traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros'));
if ($traitable) {
- if (!count($nodes = $this->getNode('body'))) {
- $nodes = new Twig_Node(array($this->getNode('body')));
+ if ($this->getNode('body') instanceof Twig_Node_Body) {
+ $nodes = $this->getNode('body')->getNode(0);
+ } else {
+ $nodes = $this->getNode('body');
+ }
+
+ if (!count($nodes)) {
+ $nodes = new Twig_Node(array($nodes));
}
foreach ($nodes as $node) {
+ if (!count($node)) {
+ continue;
+ }
+
if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
continue;
}
@@ -268,16 +322,31 @@ class Twig_Node_Module extends Twig_Node
}
}
+ if ($traitable) {
+ return;
+ }
+
$compiler
->write("public function isTraitable()\n", "{\n")
->indent()
->write(sprintf("return %s;\n", $traitable ? 'true' : 'false'))
->outdent()
+ ->write("}\n\n")
+ ;
+ }
+
+ protected function compileDebugInfo(Twig_Compiler $compiler)
+ {
+ $compiler
+ ->write("public function getDebugInfo()\n", "{\n")
+ ->indent()
+ ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true))))
+ ->outdent()
->write("}\n")
;
}
- public function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
+ protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
{
if ($node instanceof Twig_Node_Expression_Constant) {
$compiler
diff --git a/inc/lib/Twig/Node/Print.php b/inc/lib/Twig/Node/Print.php
index 766725ff..b0c41d1d 100644
--- a/inc/lib/Twig/Node/Print.php
+++ b/inc/lib/Twig/Node/Print.php
@@ -13,8 +13,7 @@
/**
* Represents a node that outputs an expression.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface
{
diff --git a/inc/lib/Twig/Node/Sandbox.php b/inc/lib/Twig/Node/Sandbox.php
index cbfcb411..8cf3ed44 100644
--- a/inc/lib/Twig/Node/Sandbox.php
+++ b/inc/lib/Twig/Node/Sandbox.php
@@ -12,8 +12,7 @@
/**
* Represents a sandbox node.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Sandbox extends Twig_Node
{
diff --git a/inc/lib/Twig/Node/SandboxedModule.php b/inc/lib/Twig/Node/SandboxedModule.php
index 36d9f198..be1f5daa 100644
--- a/inc/lib/Twig/Node/SandboxedModule.php
+++ b/inc/lib/Twig/Node/SandboxedModule.php
@@ -13,8 +13,7 @@
/**
* Represents a module node.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_SandboxedModule extends Twig_Node_Module
{
@@ -24,7 +23,9 @@ class Twig_Node_SandboxedModule extends Twig_Node_Module
public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags, array $usedFunctions)
{
- parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('filename'), $node->getLine(), $node->getNodeTag());
+ parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('embedded_templates'), $node->getAttribute('filename'), $node->getLine(), $node->getNodeTag());
+
+ $this->setAttribute('index', $node->getAttribute('index'));
$this->usedFilters = $usedFilters;
$this->usedTags = $usedTags;
@@ -33,9 +34,7 @@ class Twig_Node_SandboxedModule extends Twig_Node_Module
protected function compileDisplayBody(Twig_Compiler $compiler)
{
- if (null === $this->getNode('parent')) {
- $compiler->write("\$this->checkSecurity();\n");
- }
+ $compiler->write("\$this->checkSecurity();\n");
parent::compileDisplayBody($compiler);
}
@@ -45,7 +44,7 @@ class Twig_Node_SandboxedModule extends Twig_Node_Module
parent::compileDisplayFooter($compiler);
$compiler
- ->write("protected function checkSecurity() {\n")
+ ->write("protected function checkSecurity()\n", "{\n")
->indent()
->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
->indent()
@@ -54,16 +53,6 @@ class Twig_Node_SandboxedModule extends Twig_Node_Module
->write(!$this->usedFunctions ? "array()\n" : "array('".implode('\', \'', $this->usedFunctions)."')\n")
->outdent()
->write(");\n")
- ;
-
- if (null !== $this->getNode('parent')) {
- $compiler
- ->raw("\n")
- ->write("\$this->parent->checkSecurity();\n")
- ;
- }
-
- $compiler
->outdent()
->write("}\n\n")
;
diff --git a/inc/lib/Twig/Node/SandboxedPrint.php b/inc/lib/Twig/Node/SandboxedPrint.php
index 77730d8c..73dfaa96 100644
--- a/inc/lib/Twig/Node/SandboxedPrint.php
+++ b/inc/lib/Twig/Node/SandboxedPrint.php
@@ -17,8 +17,7 @@
* and if the sandbox is enabled, we need to check that the __toString()
* method is allowed if 'article' is an object.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_SandboxedPrint extends Twig_Node_Print
{
diff --git a/inc/lib/Twig/Node/Set.php b/inc/lib/Twig/Node/Set.php
index 9913664f..4c9c16ce 100644
--- a/inc/lib/Twig/Node/Set.php
+++ b/inc/lib/Twig/Node/Set.php
@@ -12,8 +12,7 @@
/**
* Represents a set node.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Set extends Twig_Node
{
@@ -67,7 +66,7 @@ class Twig_Node_Set extends Twig_Node
$compiler->subcompile($this->getNode('names'), false);
if ($this->getAttribute('capture')) {
- $compiler->raw(" = new Twig_Markup(ob_get_clean())");
+ $compiler->raw(" = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())");
}
}
@@ -87,9 +86,9 @@ class Twig_Node_Set extends Twig_Node
} else {
if ($this->getAttribute('safe')) {
$compiler
- ->raw("new Twig_Markup(")
+ ->raw("('' === \$tmp = ")
->subcompile($this->getNode('values'))
- ->raw(")")
+ ->raw(") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())")
;
} else {
$compiler->subcompile($this->getNode('values'));
diff --git a/inc/lib/Twig/Node/SetTemp.php b/inc/lib/Twig/Node/SetTemp.php
new file mode 100644
index 00000000..3bdd1cb7
--- /dev/null
+++ b/inc/lib/Twig/Node/SetTemp.php
@@ -0,0 +1,35 @@
+<?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_SetTemp extends Twig_Node
+{
+ public function __construct($name, $lineno)
+ {
+ parent::__construct(array(), array('name' => $name), $lineno);
+ }
+
+ public function compile(Twig_Compiler $compiler)
+ {
+ $name = $this->getAttribute('name');
+ $compiler
+ ->addDebugInfo($this)
+ ->write('if (isset($context[')
+ ->string($name)
+ ->raw('])) { $_')
+ ->raw($name)
+ ->raw('_ = $context[')
+ ->repr($name)
+ ->raw(']; } else { $_')
+ ->raw($name)
+ ->raw("_ = null; }\n")
+ ;
+ }
+}
diff --git a/inc/lib/Twig/Node/Spaceless.php b/inc/lib/Twig/Node/Spaceless.php
index 46013466..7555fa0f 100644
--- a/inc/lib/Twig/Node/Spaceless.php
+++ b/inc/lib/Twig/Node/Spaceless.php
@@ -14,8 +14,7 @@
*
* It removes spaces between HTML tags.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Spaceless extends Twig_Node
{
diff --git a/inc/lib/Twig/Node/Text.php b/inc/lib/Twig/Node/Text.php
index 0c1c0928..21bdcea1 100644
--- a/inc/lib/Twig/Node/Text.php
+++ b/inc/lib/Twig/Node/Text.php
@@ -13,8 +13,7 @@
/**
* Represents a text node.
*
- * @package twig
- * @author Fabien Potencier <fabien@symfony.com>
+ * @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Text extends Twig_Node implements Twig_NodeOutputInterface
{