Browse Source

Twig update to latest Twig 1.x legacy as per vichan

pull/40/head
Benjamin Southall 5 years ago
parent
commit
f79395851b
  1. 18
      inc/lib/Twig/Autoloader.php
  2. 54
      inc/lib/Twig/BaseNodeVisitor.php
  3. 93
      inc/lib/Twig/Cache/Filesystem.php
  4. 40
      inc/lib/Twig/Cache/Null.php
  5. 58
      inc/lib/Twig/CacheInterface.php
  6. 90
      inc/lib/Twig/Compiler.php
  7. 9
      inc/lib/Twig/CompilerInterface.php
  8. 39
      inc/lib/Twig/ContainerRuntimeLoader.php
  9. 802
      inc/lib/Twig/Environment.php
  10. 172
      inc/lib/Twig/Error.php
  11. 15
      inc/lib/Twig/Error/Loader.php
  12. 6
      inc/lib/Twig/Error/Runtime.php
  13. 39
      inc/lib/Twig/Error/Syntax.php
  14. 9
      inc/lib/Twig/ExistsLoaderInterface.php
  15. 341
      inc/lib/Twig/ExpressionParser.php
  16. 54
      inc/lib/Twig/Extension.php
  17. 809
      inc/lib/Twig/Extension/Core.php
  18. 22
      inc/lib/Twig/Extension/Debug.php
  19. 61
      inc/lib/Twig/Extension/Escaper.php
  20. 24
      inc/lib/Twig/Extension/GlobalsInterface.php
  21. 24
      inc/lib/Twig/Extension/InitRuntimeInterface.php
  22. 14
      inc/lib/Twig/Extension/Optimizer.php
  23. 49
      inc/lib/Twig/Extension/Profiler.php
  24. 27
      inc/lib/Twig/Extension/Sandbox.php
  25. 45
      inc/lib/Twig/Extension/Staging.php
  26. 37
      inc/lib/Twig/Extension/StringLoader.php
  27. 23
      inc/lib/Twig/ExtensionInterface.php
  28. 39
      inc/lib/Twig/FactoryRuntimeLoader.php
  29. 60
      inc/lib/Twig/FileExtensionEscapingStrategy.php
  30. 13
      inc/lib/Twig/Filter.php
  31. 5
      inc/lib/Twig/Filter/Function.php
  32. 7
      inc/lib/Twig/Filter/Method.php
  33. 5
      inc/lib/Twig/Filter/Node.php
  34. 3
      inc/lib/Twig/FilterCallableInterface.php
  35. 3
      inc/lib/Twig/FilterInterface.php
  36. 9
      inc/lib/Twig/Function.php
  37. 7
      inc/lib/Twig/Function/Function.php
  38. 9
      inc/lib/Twig/Function/Method.php
  39. 5
      inc/lib/Twig/Function/Node.php
  40. 3
      inc/lib/Twig/FunctionCallableInterface.php
  41. 5
      inc/lib/Twig/FunctionInterface.php
  42. 127
      inc/lib/Twig/Lexer.php
  43. 15
      inc/lib/Twig/LexerInterface.php
  44. 42
      inc/lib/Twig/Loader/Array.php
  45. 65
      inc/lib/Twig/Loader/Chain.php
  46. 158
      inc/lib/Twig/Loader/Filesystem.php
  47. 33
      inc/lib/Twig/Loader/String.php
  48. 13
      inc/lib/Twig/LoaderInterface.php
  49. 4
      inc/lib/Twig/Markup.php
  50. 124
      inc/lib/Twig/Node.php
  51. 9
      inc/lib/Twig/Node/AutoEscape.php
  52. 11
      inc/lib/Twig/Node/Block.php
  53. 11
      inc/lib/Twig/Node/BlockReference.php
  54. 4
      inc/lib/Twig/Node/Body.php
  55. 80
      inc/lib/Twig/Node/CheckSecurity.php
  56. 9
      inc/lib/Twig/Node/Do.php
  57. 20
      inc/lib/Twig/Node/Embed.php
  58. 6
      inc/lib/Twig/Node/Expression.php
  59. 13
      inc/lib/Twig/Node/Expression/Array.php
  60. 11
      inc/lib/Twig/Node/Expression/AssignName.php
  61. 11
      inc/lib/Twig/Node/Expression/Binary.php
  62. 6
      inc/lib/Twig/Node/Expression/Binary/Add.php
  63. 6
      inc/lib/Twig/Node/Expression/Binary/And.php
  64. 6
      inc/lib/Twig/Node/Expression/Binary/BitwiseAnd.php
  65. 6
      inc/lib/Twig/Node/Expression/Binary/BitwiseOr.php
  66. 6
      inc/lib/Twig/Node/Expression/Binary/BitwiseXor.php
  67. 6
      inc/lib/Twig/Node/Expression/Binary/Concat.php
  68. 6
      inc/lib/Twig/Node/Expression/Binary/Div.php
  69. 32
      inc/lib/Twig/Node/Expression/Binary/EndsWith.php
  70. 4
      inc/lib/Twig/Node/Expression/Binary/Equal.php
  71. 13
      inc/lib/Twig/Node/Expression/Binary/FloorDiv.php
  72. 4
      inc/lib/Twig/Node/Expression/Binary/Greater.php
  73. 4
      inc/lib/Twig/Node/Expression/Binary/GreaterEqual.php
  74. 9
      inc/lib/Twig/Node/Expression/Binary/In.php
  75. 4
      inc/lib/Twig/Node/Expression/Binary/Less.php
  76. 4
      inc/lib/Twig/Node/Expression/Binary/LessEqual.php
  77. 30
      inc/lib/Twig/Node/Expression/Binary/Matches.php
  78. 6
      inc/lib/Twig/Node/Expression/Binary/Mod.php
  79. 6
      inc/lib/Twig/Node/Expression/Binary/Mul.php
  80. 4
      inc/lib/Twig/Node/Expression/Binary/NotEqual.php
  81. 9
      inc/lib/Twig/Node/Expression/Binary/NotIn.php
  82. 6
      inc/lib/Twig/Node/Expression/Binary/Or.php
  83. 13
      inc/lib/Twig/Node/Expression/Binary/Power.php
  84. 9
      inc/lib/Twig/Node/Expression/Binary/Range.php
  85. 32
      inc/lib/Twig/Node/Expression/Binary/StartsWith.php
  86. 6
      inc/lib/Twig/Node/Expression/Binary/Sub.php
  87. 84
      inc/lib/Twig/Node/Expression/BlockReference.php
  88. 209
      inc/lib/Twig/Node/Expression/Call.php
  89. 6
      inc/lib/Twig/Node/Expression/Conditional.php
  90. 6
      inc/lib/Twig/Node/Expression/Constant.php
  91. 11
      inc/lib/Twig/Node/Expression/ExtensionReference.php
  92. 9
      inc/lib/Twig/Node/Expression/Filter.php
  93. 12
      inc/lib/Twig/Node/Expression/Filter/Default.php
  94. 16
      inc/lib/Twig/Node/Expression/Function.php
  95. 49
      inc/lib/Twig/Node/Expression/GetAttr.php
  96. 4
      inc/lib/Twig/Node/Expression/MethodCall.php
  97. 28
      inc/lib/Twig/Node/Expression/Name.php
  98. 48
      inc/lib/Twig/Node/Expression/NullCoalesce.php
  99. 17
      inc/lib/Twig/Node/Expression/Parent.php
  100. 4
      inc/lib/Twig/Node/Expression/TempName.php

18
inc/lib/Twig/Autoloader.php

@ -3,37 +3,43 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
@trigger_error('The Twig_Autoloader class is deprecated since version 1.21 and will be removed in 2.0. Use Composer instead.', E_USER_DEPRECATED);
/** /**
* Autoloads Twig classes. * Autoloads Twig classes.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.21 and will be removed in 2.0. Use Composer instead. 2.0.
*/ */
class Twig_Autoloader class Twig_Autoloader
{ {
/** /**
* Registers Twig_Autoloader as an SPL autoloader. * Registers Twig_Autoloader as an SPL autoloader.
* *
* @param Boolean $prepend Whether to prepend the autoloader or not. * @param bool $prepend whether to prepend the autoloader or not
*/ */
public static function register($prepend = false) public static function register($prepend = false)
{ {
if (version_compare(phpversion(), '5.3.0', '>=')) { @trigger_error('Using Twig_Autoloader is deprecated since version 1.21. Use Composer instead.', E_USER_DEPRECATED);
spl_autoload_register(array(new self, 'autoload'), true, $prepend);
if (PHP_VERSION_ID < 50300) {
spl_autoload_register(array(__CLASS__, 'autoload'));
} else { } else {
spl_autoload_register(array(new self, 'autoload')); spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
} }
} }
/** /**
* Handles autoloading of classes. * Handles autoloading of classes.
* *
* @param string $class A class name. * @param string $class a class name
*/ */
public static function autoload($class) public static function autoload($class)
{ {

54
inc/lib/Twig/BaseNodeVisitor.php

@ -0,0 +1,54 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Twig_BaseNodeVisitor can be used to make node visitors compatible with Twig 1.x and 2.x.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class Twig_BaseNodeVisitor implements Twig_NodeVisitorInterface
{
final public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if (!$node instanceof Twig_Node) {
throw new LogicException('Twig_BaseNodeVisitor only supports Twig_Node instances.');
}
return $this->doEnterNode($node, $env);
}
final public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if (!$node instanceof Twig_Node) {
throw new LogicException('Twig_BaseNodeVisitor only supports Twig_Node instances.');
}
return $this->doLeaveNode($node, $env);
}
/**
* Called before child nodes are visited.
*
* @return Twig_Node The modified node
*/
abstract protected function doEnterNode(Twig_Node $node, Twig_Environment $env);
/**
* Called after child nodes are visited.
*
* @return Twig_Node|false The modified node or false if the node must be removed
*/
abstract protected function doLeaveNode(Twig_Node $node, Twig_Environment $env);
}
class_alias('Twig_BaseNodeVisitor', 'Twig\NodeVisitor\AbstractNodeVisitor', false);
class_exists('Twig_Environment');
class_exists('Twig_Node');

93
inc/lib/Twig/Cache/Filesystem.php

@ -0,0 +1,93 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Implements a cache on the filesystem.
*
* @author Andrew Tch <andrew@noop.lv>
*/
class Twig_Cache_Filesystem implements Twig_CacheInterface
{
const FORCE_BYTECODE_INVALIDATION = 1;
private $directory;
private $options;
/**
* @param $directory string The root cache directory
* @param $options int A set of options
*/
public function __construct($directory, $options = 0)
{
$this->directory = rtrim($directory, '\/').'/';
$this->options = $options;
}
public function generateKey($name, $className)
{
$hash = hash('sha256', $className);
return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
}
public function load($key)
{
if (file_exists($key)) {
@include_once $key;
}
}
public function write($key, $content)
{
$dir = dirname($key);
if (!is_dir($dir)) {
if (false === @mkdir($dir, 0777, true)) {
if (PHP_VERSION_ID >= 50300) {
clearstatcache(true, $dir);
}
if (!is_dir($dir)) {
throw new RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir));
}
}
} elseif (!is_writable($dir)) {
throw new RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir));
}
$tmpFile = tempnam($dir, basename($key));
if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $key)) {
@chmod($key, 0666 & ~umask());
if (self::FORCE_BYTECODE_INVALIDATION == ($this->options & self::FORCE_BYTECODE_INVALIDATION)) {
// Compile cached file into bytecode cache
if (function_exists('opcache_invalidate')) {
opcache_invalidate($key, true);
} elseif (function_exists('apc_compile_file')) {
apc_compile_file($key);
}
}
return;
}
throw new RuntimeException(sprintf('Failed to write cache file "%s".', $key));
}
public function getTimestamp($key)
{
if (!file_exists($key)) {
return 0;
}
return (int) @filemtime($key);
}
}
class_alias('Twig_Cache_Filesystem', 'Twig\Cache\FilesystemCache', false);

40
inc/lib/Twig/Cache/Null.php

@ -0,0 +1,40 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Implements a no-cache strategy.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Cache_Null implements Twig_CacheInterface
{
public function generateKey($name, $className)
{
return '';
}
public function write($key, $content)
{
}
public function load($key)
{
}
public function getTimestamp($key)
{
return 0;
}
}
class_alias('Twig_Cache_Null', 'Twig\Cache\NullCache', false);

58
inc/lib/Twig/CacheInterface.php

@ -0,0 +1,58 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface implemented by cache classes.
*
* It is highly recommended to always store templates on the filesystem to
* benefit from the PHP opcode cache. This interface is mostly useful if you
* need to implement a custom strategy for storing templates on the filesystem.
*
* @author Andrew Tch <andrew@noop.lv>
*/
interface Twig_CacheInterface
{
/**
* Generates a cache key for the given template class name.
*
* @param string $name The template name
* @param string $className The template class name
*
* @return string
*/
public function generateKey($name, $className);
/**
* Writes the compiled template to cache.
*
* @param string $key The cache key
* @param string $content The template representation as a PHP class
*/
public function write($key, $content);
/**
* Loads a template from the cache.
*
* @param string $key The cache key
*/
public function load($key);
/**
* Returns the modification timestamp of a key.
*
* @param string $key The cache key
*
* @return int
*/
public function getTimestamp($key);
}
class_alias('Twig_CacheInterface', 'Twig\Cache\CacheInterface', false);

90
inc/lib/Twig/Compiler.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -21,31 +21,31 @@ class Twig_Compiler implements Twig_CompilerInterface
protected $source; protected $source;
protected $indentation; protected $indentation;
protected $env; protected $env;
protected $debugInfo; protected $debugInfo = array();
protected $sourceOffset; protected $sourceOffset;
protected $sourceLine; protected $sourceLine;
protected $filename; protected $filename;
private $varNameSalt = 0;
/**
* Constructor.
*
* @param Twig_Environment $env The twig environment instance
*/
public function __construct(Twig_Environment $env) public function __construct(Twig_Environment $env)
{ {
$this->env = $env; $this->env = $env;
$this->debugInfo = array();
} }
/**
* @deprecated since 1.25 (to be removed in 2.0)
*/
public function getFilename() public function getFilename()
{ {
@trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED);
return $this->filename; return $this->filename;
} }
/** /**
* Returns the environment instance related to this compiler. * Returns the environment instance related to this compiler.
* *
* @return Twig_Environment The environment instance * @return Twig_Environment
*/ */
public function getEnvironment() public function getEnvironment()
{ {
@ -66,21 +66,24 @@ class Twig_Compiler implements Twig_CompilerInterface
* Compiles a node. * Compiles a node.
* *
* @param Twig_NodeInterface $node The node to compile * @param Twig_NodeInterface $node The node to compile
* @param integer $indentation The current indentation * @param int $indentation The current indentation
* *
* @return Twig_Compiler The current compiler instance * @return $this
*/ */
public function compile(Twig_NodeInterface $node, $indentation = 0) public function compile(Twig_NodeInterface $node, $indentation = 0)
{ {
$this->lastLine = null; $this->lastLine = null;
$this->source = ''; $this->source = '';
$this->debugInfo = array();
$this->sourceOffset = 0; $this->sourceOffset = 0;
// source code starts at 1 (as we then increment it when we encounter new lines) // source code starts at 1 (as we then increment it when we encounter new lines)
$this->sourceLine = 1; $this->sourceLine = 1;
$this->indentation = $indentation; $this->indentation = $indentation;
$this->varNameSalt = 0;
if ($node instanceof Twig_Node_Module) { if ($node instanceof Twig_Node_Module) {
$this->filename = $node->getAttribute('filename'); // to be removed in 2.0
$this->filename = $node->getTemplateName();
} }
$node->compile($this); $node->compile($this);
@ -91,7 +94,7 @@ class Twig_Compiler implements Twig_CompilerInterface
public function subcompile(Twig_NodeInterface $node, $raw = true) public function subcompile(Twig_NodeInterface $node, $raw = true)
{ {
if (false === $raw) { if (false === $raw) {
$this->addIndentation(); $this->source .= str_repeat(' ', $this->indentation * 4);
} }
$node->compile($this); $node->compile($this);
@ -104,7 +107,7 @@ class Twig_Compiler implements Twig_CompilerInterface
* *
* @param string $string The string * @param string $string The string
* *
* @return Twig_Compiler The current compiler instance * @return $this
*/ */
public function raw($string) public function raw($string)
{ {
@ -116,14 +119,13 @@ class Twig_Compiler implements Twig_CompilerInterface
/** /**
* Writes a string to the compiled code by adding indentation. * Writes a string to the compiled code by adding indentation.
* *
* @return Twig_Compiler The current compiler instance * @return $this
*/ */
public function write() public function write()
{ {
$strings = func_get_args(); $strings = func_get_args();
foreach ($strings as $string) { foreach ($strings as $string) {
$this->addIndentation(); $this->source .= str_repeat(' ', $this->indentation * 4).$string;
$this->source .= $string;
} }
return $this; return $this;
@ -132,10 +134,14 @@ class Twig_Compiler implements Twig_CompilerInterface
/** /**
* Appends an indentation to the current PHP code after compilation. * Appends an indentation to the current PHP code after compilation.
* *
* @return Twig_Compiler The current compiler instance * @return $this
*
* @deprecated since 1.27 (to be removed in 2.0).
*/ */
public function addIndentation() public function addIndentation()
{ {
@trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use write(\'\') instead.', E_USER_DEPRECATED);
$this->source .= str_repeat(' ', $this->indentation * 4); $this->source .= str_repeat(' ', $this->indentation * 4);
return $this; return $this;
@ -146,7 +152,7 @@ class Twig_Compiler implements Twig_CompilerInterface
* *
* @param string $value The string * @param string $value The string
* *
* @return Twig_Compiler The current compiler instance * @return $this
*/ */
public function string($value) public function string($value)
{ {
@ -160,12 +166,12 @@ class Twig_Compiler implements Twig_CompilerInterface
* *
* @param mixed $value The value to convert * @param mixed $value The value to convert
* *
* @return Twig_Compiler The current compiler instance * @return $this
*/ */
public function repr($value) public function repr($value)
{ {
if (is_int($value) || is_float($value)) { if (is_int($value) || is_float($value)) {
if (false !== $locale = setlocale(LC_NUMERIC, 0)) { if (false !== $locale = setlocale(LC_NUMERIC, '0')) {
setlocale(LC_NUMERIC, 'C'); setlocale(LC_NUMERIC, 'C');
} }
@ -181,14 +187,14 @@ class Twig_Compiler implements Twig_CompilerInterface
} elseif (is_array($value)) { } elseif (is_array($value)) {
$this->raw('array('); $this->raw('array(');
$first = true; $first = true;
foreach ($value as $key => $value) { foreach ($value as $key => $v) {
if (!$first) { if (!$first) {
$this->raw(', '); $this->raw(', ');
} }
$first = false; $first = false;
$this->repr($key); $this->repr($key);
$this->raw(' => '); $this->raw(' => ');
$this->repr($value); $this->repr($v);
} }
$this->raw(')'); $this->raw(')');
} else { } else {
@ -201,28 +207,28 @@ class Twig_Compiler implements Twig_CompilerInterface
/** /**
* Adds debugging information. * Adds debugging information.
* *
* @param Twig_NodeInterface $node The related twig node * @return $this
*
* @return Twig_Compiler The current compiler instance
*/ */
public function addDebugInfo(Twig_NodeInterface $node) public function addDebugInfo(Twig_NodeInterface $node)
{ {
if ($node->getLine() != $this->lastLine) { if ($node->getTemplateLine() != $this->lastLine) {
$this->write("// line {$node->getLine()}\n"); $this->write(sprintf("// line %d\n", $node->getTemplateLine()));
// when mbstring.func_overload is set to 2 // when mbstring.func_overload is set to 2
// mb_substr_count() replaces substr_count() // mb_substr_count() replaces substr_count()
// but they have different signatures! // but they have different signatures!
if (((int) ini_get('mbstring.func_overload')) & 2) { if (((int) ini_get('mbstring.func_overload')) & 2) {
@trigger_error('Support for having "mbstring.func_overload" different from 0 is deprecated version 1.29 and will be removed in 2.0.', E_USER_DEPRECATED);
// this is much slower than the "right" version // this is much slower than the "right" version
$this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n"); $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
} else { } else {
$this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset); $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
} }
$this->sourceOffset = strlen($this->source); $this->sourceOffset = strlen($this->source);
$this->debugInfo[$this->sourceLine] = $node->getLine(); $this->debugInfo[$this->sourceLine] = $node->getTemplateLine();
$this->lastLine = $node->getLine(); $this->lastLine = $node->getTemplateLine();
} }
return $this; return $this;
@ -230,15 +236,17 @@ class Twig_Compiler implements Twig_CompilerInterface
public function getDebugInfo() public function getDebugInfo()
{ {
ksort($this->debugInfo);
return $this->debugInfo; return $this->debugInfo;
} }
/** /**
* Indents the generated code. * Indents the generated code.
* *
* @param integer $step The number of indentation to add * @param int $step The number of indentation to add
* *
* @return Twig_Compiler The current compiler instance * @return $this
*/ */
public function indent($step = 1) public function indent($step = 1)
{ {
@ -250,19 +258,29 @@ class Twig_Compiler implements Twig_CompilerInterface
/** /**
* Outdents the generated code. * Outdents the generated code.
* *
* @param integer $step The number of indentation to remove * @param int $step The number of indentation to remove
*
* @return $this
* *
* @return Twig_Compiler The current compiler instance * @throws LogicException When trying to outdent too much so the indentation would become negative
*/ */
public function outdent($step = 1) public function outdent($step = 1)
{ {
// can't outdent by more steps than the current indentation level // can't outdent by more steps than the current indentation level
if ($this->indentation < $step) { if ($this->indentation < $step) {
throw new LogicException('Unable to call outdent() as the indentation would become negative'); throw new LogicException('Unable to call outdent() as the indentation would become negative.');
} }
$this->indentation -= $step; $this->indentation -= $step;
return $this; return $this;
} }
public function getVarName()
{
return sprintf('__internal_%s', hash('sha256', __METHOD__.$this->varNameSalt++));
}
} }
class_alias('Twig_Compiler', 'Twig\Compiler', false);
class_exists('Twig_Node');

9
inc/lib/Twig/CompilerInterface.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -13,16 +13,15 @@
* Interface implemented by compiler classes. * Interface implemented by compiler classes.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0) *
* @deprecated since 1.12 (to be removed in 3.0)
*/ */
interface Twig_CompilerInterface interface Twig_CompilerInterface
{ {
/** /**
* Compiles a node. * Compiles a node.
* *
* @param Twig_NodeInterface $node The node to compile * @return $this
*
* @return Twig_CompilerInterface The current compiler instance
*/ */
public function compile(Twig_NodeInterface $node); public function compile(Twig_NodeInterface $node);

39
inc/lib/Twig/ContainerRuntimeLoader.php

@ -0,0 +1,39 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Psr\Container\ContainerInterface;
/**
* Lazily loads Twig runtime implementations from a PSR-11 container.
*
* Note that the runtime services MUST use their class names as identifiers.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class Twig_ContainerRuntimeLoader implements Twig_RuntimeLoaderInterface
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function load($class)
{
if ($this->container->has($class)) {
return $this->container->get($class);
}
}
}
class_alias('Twig_ContainerRuntimeLoader', 'Twig\RuntimeLoader\ContainerRuntimeLoader', false);

802
inc/lib/Twig/Environment.php

File diff suppressed because it is too large

172
inc/lib/Twig/Error.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -25,8 +25,8 @@
* and line number) yourself by passing them to the constructor. If some or all * and line number) yourself by passing them to the constructor. If some or all
* these information are not available from where you throw the exception, then * these information are not available from where you throw the exception, then
* this class will guess them automatically (when the line number is set to -1 * this class will guess them automatically (when the line number is set to -1
* and/or the filename is set to null). As this is a costly operation, this * and/or the name is set to null). As this is a costly operation, this
* can be disabled by passing false for both the filename and the line number * can be disabled by passing false for both the name and the line number
* when creating a new instance of this class. * when creating a new instance of this class.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
@ -34,30 +34,44 @@
class Twig_Error extends Exception class Twig_Error extends Exception
{ {
protected $lineno; protected $lineno;
// to be renamed to name in 2.0
protected $filename; protected $filename;
protected $rawMessage; protected $rawMessage;
protected $previous; protected $previous;
private $sourcePath;
private $sourceCode;
/** /**
* Constructor. * Constructor.
* *
* Set both the line number and the filename to false to * Set both the line number and the name to false to
* disable automatic guessing of the original template name * disable automatic guessing of the original template name
* and line number. * and line number.
* *
* Set the line number to -1 to enable its automatic guessing. * Set the line number to -1 to enable its automatic guessing.
* Set the filename to null to enable its automatic guessing. * Set the name to null to enable its automatic guessing.
* *
* By default, automatic guessing is enabled. * By default, automatic guessing is enabled.
* *
* @param string $message The error message * @param string $message The error message
* @param integer $lineno The template line where the error occurred * @param int $lineno The template line where the error occurred
* @param string $filename The template file name where the error occurred * @param Twig_Source|string|null $source The source context where the error occurred
* @param Exception $previous The previous exception * @param Exception $previous The previous exception
*/ */
public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null) public function __construct($message, $lineno = -1, $source = null, Exception $previous = null)
{ {
if (version_compare(PHP_VERSION, '5.3.0', '<')) { if (null === $source) {
$name = null;
} elseif (!$source instanceof Twig_Source) {
// for compat with the Twig C ext., passing the template name as string is accepted
$name = $source;
} else {
$name = $source->getName();
$this->sourceCode = $source->getCode();
$this->sourcePath = $source->getPath();
}
if (PHP_VERSION_ID < 50300) {
$this->previous = $previous; $this->previous = $previous;
parent::__construct(''); parent::__construct('');
} else { } else {
@ -65,9 +79,9 @@ class Twig_Error extends Exception
} }
$this->lineno = $lineno; $this->lineno = $lineno;
$this->filename = $filename; $this->filename = $name;
if (-1 === $this->lineno || null === $this->filename) { if (-1 === $lineno || null === $name || null === $this->sourcePath) {
$this->guessTemplateInfo(); $this->guessTemplateInfo();
} }
@ -87,23 +101,62 @@ class Twig_Error extends Exception
} }
/** /**
* Gets the filename where the error occurred. * Gets the logical name where the error occurred.
*
* @return string The name
* *
* @return string The filename * @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead.
*/ */
public function getTemplateFile() public function getTemplateFile()
{ {
@trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
return $this->filename; return $this->filename;
} }
/** /**
* Sets the filename where the error occurred. * Sets the logical name where the error occurred.
*
* @param string $name The name
* *
* @param string $filename The filename * @deprecated since 1.27 (to be removed in 2.0). Use setSourceContext() instead.
*/ */
public function setTemplateFile($filename) public function setTemplateFile($name)
{ {
$this->filename = $filename; @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
$this->filename = $name;
$this->updateRepr();
}
/**
* Gets the logical name where the error occurred.
*
* @return string The name
*
* @deprecated since 1.29 (to be removed in 2.0). Use getSourceContext() instead.
*/
public function getTemplateName()
{
@trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
return $this->filename;
}
/**
* Sets the logical name where the error occurred.
*
* @param string $name The name
*
* @deprecated since 1.29 (to be removed in 2.0). Use setSourceContext() instead.
*/
public function setTemplateName($name)
{
@trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
$this->filename = $name;
$this->sourceCode = $this->sourcePath = null;
$this->updateRepr(); $this->updateRepr();
} }
@ -111,7 +164,7 @@ class Twig_Error extends Exception
/** /**
* Gets the template line where the error occurred. * Gets the template line where the error occurred.
* *
* @return integer The template line * @return int The template line
*/ */
public function getTemplateLine() public function getTemplateLine()
{ {
@ -121,7 +174,7 @@ class Twig_Error extends Exception
/** /**
* Sets the template line where the error occurred. * Sets the template line where the error occurred.
* *
* @param integer $lineno The template line * @param int $lineno The template line
*/ */
public function setTemplateLine($lineno) public function setTemplateLine($lineno)
{ {
@ -130,6 +183,32 @@ class Twig_Error extends Exception
$this->updateRepr(); $this->updateRepr();
} }
/**
* Gets the source context of the Twig template where the error occurred.
*
* @return Twig_Source|null
*/
public function getSourceContext()
{
return $this->filename ? new Twig_Source($this->sourceCode, $this->filename, $this->sourcePath) : null;
}
/**
* Sets the source context of the Twig template where the error occurred.
*/
public function setSourceContext(Twig_Source $source = null)
{
if (null === $source) {
$this->sourceCode = $this->filename = $this->sourcePath = null;
} else {
$this->sourceCode = $source->getCode();
$this->filename = $source->getName();
$this->sourcePath = $source->getPath();
}
$this->updateRepr();
}
public function guess() public function guess()
{ {
$this->guessTemplateInfo(); $this->guessTemplateInfo();
@ -155,23 +234,45 @@ class Twig_Error extends Exception
throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method)); throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
} }
public function appendMessage($rawMessage)
{
$this->rawMessage .= $rawMessage;
$this->updateRepr();
}
/**
* @internal
*/
protected function updateRepr() protected function updateRepr()
{ {
$this->message = $this->rawMessage; $this->message = $this->rawMessage;
if ($this->sourcePath && $this->lineno > 0) {
$this->file = $this->sourcePath;
$this->line = $this->lineno;
return;
}
$dot = false; $dot = false;
if ('.' === substr($this->message, -1)) { if ('.' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1); $this->message = substr($this->message, 0, -1);
$dot = true; $dot = true;
} }
$questionMark = false;
if ('?' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$questionMark = true;
}
if ($this->filename) { if ($this->filename) {
if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) { if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) {
$filename = sprintf('"%s"', $this->filename); $name = sprintf('"%s"', $this->filename);
} else { } else {
$filename = json_encode($this->filename); $name = json_encode($this->filename);
} }
$this->message .= sprintf(' in %s', $filename); $this->message .= sprintf(' in %s', $name);
} }
if ($this->lineno && $this->lineno >= 0) { if ($this->lineno && $this->lineno >= 0) {
@ -181,14 +282,21 @@ class Twig_Error extends Exception
if ($dot) { if ($dot) {
$this->message .= '.'; $this->message .= '.';
} }
if ($questionMark) {
$this->message .= '?';
}
} }
/**
* @internal
*/
protected function guessTemplateInfo() protected function guessTemplateInfo()
{ {
$template = null; $template = null;
$templateClass = null; $templateClass = null;
if (version_compare(phpversion(), '5.3.6', '>=')) { if (PHP_VERSION_ID >= 50306) {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT); $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
} else { } else {
$backtrace = debug_backtrace(); $backtrace = debug_backtrace();
@ -205,11 +313,18 @@ class Twig_Error extends Exception
} }
} }
// update template filename // update template name
if (null !== $template && null === $this->filename) { if (null !== $template && null === $this->filename) {
$this->filename = $template->getTemplateName(); $this->filename = $template->getTemplateName();
} }
// update template path if any
if (null !== $template && null === $this->sourcePath) {
$src = $template->getSourceContext();
$this->sourceCode = $src->getCode();
$this->sourcePath = $src->getPath();
}
if (null === $template || $this->lineno > -1) { if (null === $template || $this->lineno > -1) {
return; return;
} }
@ -224,6 +339,8 @@ class Twig_Error extends Exception
while ($e = array_pop($exceptions)) { while ($e = array_pop($exceptions)) {
$traces = $e->getTrace(); $traces = $e->getTrace();
array_unshift($traces, array('file' => $e->getFile(), 'line' => $e->getLine()));
while ($trace = array_shift($traces)) { while ($trace = array_shift($traces)) {
if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) { if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
continue; continue;
@ -241,3 +358,6 @@ class Twig_Error extends Exception
} }
} }
} }
class_alias('Twig_Error', 'Twig\Error\Error', false);
class_exists('Twig_Source');

15
inc/lib/Twig/Error/Loader.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -24,8 +24,17 @@
*/ */
class Twig_Error_Loader extends Twig_Error class Twig_Error_Loader extends Twig_Error
{ {
public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null) public function __construct($message, $lineno = -1, $source = null, Exception $previous = null)
{ {
parent::__construct($message, false, false, $previous); if (PHP_VERSION_ID < 50300) {
$this->previous = $previous;
Exception::__construct('');
} else {
Exception::__construct('', 0, $previous);
}
$this->appendMessage($message);
$this->setTemplateLine(false);
} }
} }
class_alias('Twig_Error_Loader', 'Twig\Error\LoaderError', false);

6
inc/lib/Twig/Error/Runtime.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -18,3 +18,5 @@
class Twig_Error_Runtime extends Twig_Error class Twig_Error_Runtime extends Twig_Error
{ {
} }
class_alias('Twig_Error_Runtime', 'Twig\Error\RuntimeError', false);

39
inc/lib/Twig/Error/Syntax.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -17,4 +17,39 @@
*/ */
class Twig_Error_Syntax extends Twig_Error class Twig_Error_Syntax extends Twig_Error
{ {
/**
* Tweaks the error message to include suggestions.
*
* @param string $name The original name of the item that does not exist
* @param array $items An array of possible items
*/
public function addSuggestions($name, array $items)
{
if (!$alternatives = self::computeAlternatives($name, $items)) {
return;
}
$this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', $alternatives)));
}
/**
* @internal
*
* To be merged with the addSuggestions() method in 2.0.
*/
public static function computeAlternatives($name, $items)
{
$alternatives = array();
foreach ($items as $item) {
$lev = levenshtein($name, $item);
if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
$alternatives[$item] = $lev;
}
}
asort($alternatives);
return array_keys($alternatives);
}
} }
class_alias('Twig_Error_Syntax', 'Twig\Error\SyntaxError', false);

9
inc/lib/Twig/ExistsLoaderInterface.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -13,7 +13,8 @@
* Adds an exists() method for loaders. * Adds an exists() method for loaders.
* *
* @author Florin Patan <florinpatan@gmail.com> * @author Florin Patan <florinpatan@gmail.com>
* @deprecated since 1.12 (to be removed in 2.0) *
* @deprecated since 1.12 (to be removed in 3.0)
*/ */
interface Twig_ExistsLoaderInterface interface Twig_ExistsLoaderInterface
{ {
@ -22,7 +23,9 @@ interface Twig_ExistsLoaderInterface
* *
* @param string $name The name of the template to check if we can load * @param string $name The name of the template to check if we can load
* *
* @return boolean If the template source code is handled by this loader or not * @return bool If the template source code is handled by this loader or not
*/ */
public function exists($name); public function exists($name);
} }
class_alias('Twig_ExistsLoaderInterface', 'Twig\Loader\ExistsLoaderInterface', false);

341
inc/lib/Twig/ExpressionParser.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -15,10 +15,12 @@
* *
* This parser implements a "Precedence climbing" algorithm. * This parser implements a "Precedence climbing" algorithm.
* *
* @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm * @see https://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
* @see http://en.wikipedia.org/wiki/Operator-precedence_parser * @see https://en.wikipedia.org/wiki/Operator-precedence_parser
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/ */
class Twig_ExpressionParser class Twig_ExpressionParser
{ {
@ -29,11 +31,23 @@ class Twig_ExpressionParser
protected $unaryOperators; protected $unaryOperators;
protected $binaryOperators; protected $binaryOperators;
public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators) private $env;
public function __construct(Twig_Parser $parser, $env = null)
{ {
$this->parser = $parser; $this->parser = $parser;
$this->unaryOperators = $unaryOperators;
$this->binaryOperators = $binaryOperators; if ($env instanceof Twig_Environment) {
$this->env = $env;
$this->unaryOperators = $env->getUnaryOperators();
$this->binaryOperators = $env->getBinaryOperators();
} else {
@trigger_error('Passing the operators as constructor arguments to '.__METHOD__.' is deprecated since version 1.27. Pass the environment instead.', E_USER_DEPRECATED);
$this->env = $parser->getEnvironment();
$this->unaryOperators = func_get_arg(1);
$this->binaryOperators = func_get_arg(2);
}
} }
public function parseExpression($precedence = 0) public function parseExpression($precedence = 0)
@ -44,7 +58,11 @@ class Twig_ExpressionParser
$op = $this->binaryOperators[$token->getValue()]; $op = $this->binaryOperators[$token->getValue()];
$this->parser->getStream()->next(); $this->parser->getStream()->next();
if (isset($op['callable'])) { if ('is not' === $token->getValue()) {
$expr = $this->parseNotTestExpression($expr);
} elseif ('is' === $token->getValue()) {
$expr = $this->parseTestExpression($expr);
} elseif (isset($op['callable'])) {
$expr = call_user_func($op['callable'], $this->parser, $expr); $expr = call_user_func($op['callable'], $this->parser, $expr);
} else { } else {
$expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']); $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
@ -86,18 +104,15 @@ class Twig_ExpressionParser
protected function parseConditionalExpression($expr) protected function parseConditionalExpression($expr)
{ {
while ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '?')) { while ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, '?')) {
$this->parser->getStream()->next(); if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
$expr2 = $this->parseExpression(); $expr2 = $this->parseExpression();
if ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) { if ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
$this->parser->getStream()->next();
$expr3 = $this->parseExpression(); $expr3 = $this->parseExpression();
} else { } else {
$expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine()); $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
} }
} else { } else {
$this->parser->getStream()->next();
$expr2 = $expr; $expr2 = $expr;
$expr3 = $this->parseExpression(); $expr3 = $this->parseExpression();
} }
@ -161,13 +176,39 @@ class Twig_ExpressionParser
$node = $this->parseStringExpression(); $node = $this->parseStringExpression();
break; break;
case Twig_Token::OPERATOR_TYPE:
if (preg_match(Twig_Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
// in this context, string operators are variable names
$this->parser->getStream()->next();
$node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
break;
} elseif (isset($this->unaryOperators[$token->getValue()])) {
$class = $this->unaryOperators[$token->getValue()]['class'];
$ref = new ReflectionClass($class);
$negClass = 'Twig_Node_Expression_Unary_Neg';
$posClass = 'Twig_Node_Expression_Unary_Pos';
if (!(in_array($ref->getName(), array($negClass, $posClass)) || $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass))) {
throw new Twig_Error_Syntax(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
}
$this->parser->getStream()->next();
$expr = $this->parsePrimaryExpression();
$node = new $class($expr, $token->getLine());
break;
}
// no break
default: default:
if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) { if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
$node = $this->parseArrayExpression(); $node = $this->parseArrayExpression();
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) { } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
$node = $this->parseHashExpression(); $node = $this->parseHashExpression();
} elseif ($token->test(Twig_Token::OPERATOR_TYPE, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) {
throw new Twig_Error_Syntax(sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
} else { } else {
throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine(), $this->parser->getFilename()); throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
} }
} }
@ -182,12 +223,10 @@ class Twig_ExpressionParser
// a string cannot be followed by another string in a single expression // a string cannot be followed by another string in a single expression
$nextCanBeString = true; $nextCanBeString = true;
while (true) { while (true) {
if ($stream->test(Twig_Token::STRING_TYPE) && $nextCanBeString) { if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) {
$token = $stream->next();
$nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
$nextCanBeString = false; $nextCanBeString = false;
} elseif ($stream->test(Twig_Token::INTERPOLATION_START_TYPE)) { } elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) {
$stream->next();
$nodes[] = $this->parseExpression(); $nodes[] = $this->parseExpression();
$stream->expect(Twig_Token::INTERPOLATION_END_TYPE); $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
$nextCanBeString = true; $nextCanBeString = true;
@ -198,7 +237,7 @@ class Twig_ExpressionParser
$expr = array_shift($nodes); $expr = array_shift($nodes);
foreach ($nodes as $node) { foreach ($nodes as $node) {
$expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine()); $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getTemplateLine());
} }
return $expr; return $expr;
@ -253,15 +292,14 @@ class Twig_ExpressionParser
// * a string -- 'a' // * a string -- 'a'
// * a name, which is equivalent to a string -- a // * a name, which is equivalent to a string -- a
// * an expression, which must be enclosed in parentheses -- (1 + 2) // * an expression, which must be enclosed in parentheses -- (1 + 2)
if ($stream->test(Twig_Token::STRING_TYPE) || $stream->test(Twig_Token::NAME_TYPE) || $stream->test(Twig_Token::NUMBER_TYPE)) { if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) {
$token = $stream->next();
$key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
} elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$key = $this->parseExpression(); $key = $this->parseExpression();
} else { } else {
$current = $stream->getCurrent(); $current = $stream->getCurrent();
throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType(), $current->getLine()), $current->getValue()), $current->getLine(), $this->parser->getFilename()); throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext());
} }
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)'); $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
@ -278,7 +316,7 @@ class Twig_ExpressionParser
{ {
while (true) { while (true) {
$token = $this->parser->getCurrentToken(); $token = $this->parser->getCurrentToken();
if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) { if (Twig_Token::PUNCTUATION_TYPE == $token->getType()) {
if ('.' == $token->getValue() || '[' == $token->getValue()) { if ('.' == $token->getValue() || '[' == $token->getValue()) {
$node = $this->parseSubscriptExpression($node); $node = $this->parseSubscriptExpression($node);
} elseif ('|' == $token->getValue()) { } elseif ('|' == $token->getValue()) {
@ -298,41 +336,46 @@ class Twig_ExpressionParser
{ {
switch ($name) { switch ($name) {
case 'parent': case 'parent':
$args = $this->parseArguments(); $this->parseArguments();
if (!count($this->parser->getBlockStack())) { if (!count($this->parser->getBlockStack())) {
throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename()); throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext());
} }
if (!$this->parser->getParent() && !$this->parser->hasTraits()) { if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename()); throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getSourceContext());
} }
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line); return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
case 'block': case 'block':
return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line); $args = $this->parseArguments();
if (count($args) < 1) {
throw new Twig_Error_Syntax('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext());
}
return new Twig_Node_Expression_BlockReference($args->getNode(0), count($args) > 1 ? $args->getNode(1) : null, $line);
case 'attribute': case 'attribute':
$args = $this->parseArguments(); $args = $this->parseArguments();
if (count($args) < 2) { if (count($args) < 2) {
throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename()); throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext());
} }
return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_Template::ANY_CALL, $line); return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line);
default: default:
$args = $this->parseArguments(true); if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
if (null !== $alias = $this->parser->getImportedSymbol('macro', $name)) { $arguments = new Twig_Node_Expression_Array(array(), $line);
return new Twig_Node_Expression_MacroCall($alias['node'], $alias['name'], $this->createArrayFromArguments($args), $line); foreach ($this->parseArguments() as $n) {
} $arguments->addElement($n);
try {
$class = $this->getFunctionNodeClass($name, $line);
} catch (Twig_Error_Syntax $e) {
if (!$this->parser->hasMacro($name)) {
throw $e;
} }
return new Twig_Node_Expression_MacroCall(new Twig_Node_Expression_Name('_self', $line), $name, $this->createArrayFromArguments($args), $line); $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
$node->setAttribute('safe', true);
return $node;
} }
$args = $this->parseArguments(true);
$class = $this->getFunctionNodeClass($name, $line);
return new $class($name, $args, $line); return new $class($name, $args, $line);
} }
} }
@ -344,33 +387,42 @@ class Twig_ExpressionParser
$lineno = $token->getLine(); $lineno = $token->getLine();
$arguments = new Twig_Node_Expression_Array(array(), $lineno); $arguments = new Twig_Node_Expression_Array(array(), $lineno);
$type = Twig_Template::ANY_CALL; $type = Twig_Template::ANY_CALL;
if ($token->getValue() == '.') { if ('.' == $token->getValue()) {
$token = $stream->next(); $token = $stream->next();
if ( if (
$token->getType() == Twig_Token::NAME_TYPE Twig_Token::NAME_TYPE == $token->getType()
|| ||
$token->getType() == Twig_Token::NUMBER_TYPE Twig_Token::NUMBER_TYPE == $token->getType()
|| ||
($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue())) (Twig_Token::OPERATOR_TYPE == $token->getType() && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
) { ) {
$arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno); $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$type = Twig_Template::METHOD_CALL;
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
}
} else { } else {
throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename()); throw new Twig_Error_Syntax('Expected name or number.', $lineno, $stream->getSourceContext());
} }
if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) { if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
if (!$arg instanceof Twig_Node_Expression_Constant) { if (!$arg instanceof Twig_Node_Expression_Constant) {
throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename()); throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext());
} }
$arguments = $this->createArrayFromArguments($this->parseArguments(true)); $name = $arg->getAttribute('value');
return new Twig_Node_Expression_MacroCall($node, $arg->getAttribute('value'), $arguments, $lineno); if ($this->parser->isReservedMacroName($name)) {
} throw new Twig_Error_Syntax(sprintf('"%s" cannot be called as macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext());
}
$node = new Twig_Node_Expression_MethodCall($node, 'get'.$name, $arguments, $lineno);
$node->setAttribute('safe', true);
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { return $node;
$type = Twig_Template::METHOD_CALL;
$arguments = $this->createArrayFromArguments($this->parseArguments());
} }
} else { } else {
$type = Twig_Template::ARRAY_CALL; $type = Twig_Template::ARRAY_CALL;
@ -384,9 +436,8 @@ class Twig_ExpressionParser
$arg = $this->parseExpression(); $arg = $this->parseExpression();
} }
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
$slice = true; $slice = true;
$stream->next();
} }
if ($slice) { if ($slice) {
@ -447,10 +498,12 @@ class Twig_ExpressionParser
/** /**
* Parses arguments. * Parses arguments.
* *
* @param Boolean $namedArguments Whether to allow named arguments or not * @param bool $namedArguments Whether to allow named arguments or not
* @param Boolean $definition Whether we are parsing arguments for a function definition * @param bool $definition Whether we are parsing arguments for a function definition
* *
* @return Twig_Node * @return Twig_Node
*
* @throws Twig_Error_Syntax
*/ */
public function parseArguments($namedArguments = false, $definition = false) public function parseArguments($namedArguments = false, $definition = false)
{ {
@ -471,10 +524,9 @@ class Twig_ExpressionParser
} }
$name = null; $name = null;
if ($namedArguments && $stream->test(Twig_Token::OPERATOR_TYPE, '=')) { if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
$token = $stream->next();
if (!$value instanceof Twig_Node_Expression_Name) { if (!$value instanceof Twig_Node_Expression_Name) {
throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename()); throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given.', get_class($value)), $token->getLine(), $stream->getSourceContext());
} }
$name = $value->getAttribute('name'); $name = $value->getAttribute('name');
@ -482,26 +534,25 @@ class Twig_ExpressionParser
$value = $this->parsePrimaryExpression(); $value = $this->parsePrimaryExpression();
if (!$this->checkConstantExpression($value)) { if (!$this->checkConstantExpression($value)) {
throw new Twig_Error_Syntax('A default value for an argument must be a constant (a boolean, a string, a number, or an array).', $token->getLine(), $this->parser->getFilename()); throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $stream->getSourceContext());
} }
} else { } else {
$value = $this->parseExpression(); $value = $this->parseExpression();
} }
} }
if ($definition && null === $name) { if ($definition) {
$name = $value->getAttribute('name'); if (null === $name) {
$value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine()); $name = $value->getAttribute('name');
} $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
if (null === $name) {
$args[] = $value;
} else {
if ($definition && isset($args[$name])) {
throw new Twig_Error_Syntax(sprintf('Arguments cannot contain the same argument name more than once ("%s" is defined twice).', $name), $token->getLine(), $this->parser->getFilename());
} }
$args[$name] = $value; $args[$name] = $value;
} else {
if (null === $name) {
$args[] = $value;
} else {
$args[$name] = $value;
}
} }
} }
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis'); $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
@ -511,18 +562,19 @@ class Twig_ExpressionParser
public function parseAssignmentExpression() public function parseAssignmentExpression()
{ {
$stream = $this->parser->getStream();
$targets = array(); $targets = array();
while (true) { while (true) {
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to'); $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
if (in_array($token->getValue(), array('true', 'false', 'none'))) { $value = $token->getValue();
throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename()); if (in_array(strtolower($value), array('true', 'false', 'none', 'null'))) {
throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext());
} }
$targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine()); $targets[] = new Twig_Node_Expression_AssignName($value, $token->getLine());
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) { if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
break; break;
} }
$this->parser->getStream()->next();
} }
return new Twig_Node($targets); return new Twig_Node($targets);
@ -533,26 +585,104 @@ class Twig_ExpressionParser
$targets = array(); $targets = array();
while (true) { while (true) {
$targets[] = $this->parseExpression(); $targets[] = $this->parseExpression();
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) { if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
break; break;
} }
$this->parser->getStream()->next();
} }
return new Twig_Node($targets); return new Twig_Node($targets);
} }
private function parseNotTestExpression(Twig_NodeInterface $node)
{
return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine());
}
private function parseTestExpression(Twig_NodeInterface $node)
{
$stream = $this->parser->getStream();
list($name, $test) = $this->getTest($node->getTemplateLine());
$class = $this->getTestNodeClass($test);
$arguments = null;
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$arguments = $this->parser->getExpressionParser()->parseArguments(true);
}
return new $class($node, $name, $arguments, $this->parser->getCurrentToken()->getLine());
}
private function getTest($line)
{
$stream = $this->parser->getStream();
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
if ($test = $this->env->getTest($name)) {
return array($name, $test);
}
if ($stream->test(Twig_Token::NAME_TYPE)) {
// try 2-words tests
$name = $name.' '.$this->parser->getCurrentToken()->getValue();
if ($test = $this->env->getTest($name)) {
$stream->next();
return array($name, $test);
}
}
$e = new Twig_Error_Syntax(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getTests()));
throw $e;
}
private function getTestNodeClass($test)
{
if ($test instanceof Twig_SimpleTest && $test->isDeprecated()) {
$stream = $this->parser->getStream();
$message = sprintf('Twig Test "%s" is deprecated', $test->getName());
if (!is_bool($test->getDeprecatedVersion())) {
$message .= sprintf(' since version %s', $test->getDeprecatedVersion());
}
if ($test->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $test->getAlternative());
}
$src = $stream->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $stream->getCurrent()->getLine());
@trigger_error($message, E_USER_DEPRECATED);
}
if ($test instanceof Twig_SimpleTest) {
return $test->getNodeClass();
}
return $test instanceof Twig_Test_Node ? $test->getClass() : 'Twig_Node_Expression_Test';
}
protected function getFunctionNodeClass($name, $line) protected function getFunctionNodeClass($name, $line)
{ {
$env = $this->parser->getEnvironment(); if (false === $function = $this->env->getFunction($name)) {
$e = new Twig_Error_Syntax(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getFunctions()));
if (false === $function = $env->getFunction($name)) { throw $e;
$message = sprintf('The function "%s" does not exist', $name); }
if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) {
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); if ($function instanceof Twig_SimpleFunction && $function->isDeprecated()) {
$message = sprintf('Twig Function "%s" is deprecated', $function->getName());
if (!is_bool($function->getDeprecatedVersion())) {
$message .= sprintf(' since version %s', $function->getDeprecatedVersion());
}
if ($function->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $function->getAlternative());
} }
$src = $this->parser->getStream()->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line);
throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename()); @trigger_error($message, E_USER_DEPRECATED);
} }
if ($function instanceof Twig_SimpleFunction) { if ($function instanceof Twig_SimpleFunction) {
@ -564,15 +694,25 @@ class Twig_ExpressionParser
protected function getFilterNodeClass($name, $line) protected function getFilterNodeClass($name, $line)
{ {
$env = $this->parser->getEnvironment(); if (false === $filter = $this->env->getFilter($name)) {
$e = new Twig_Error_Syntax(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getFilters()));
if (false === $filter = $env->getFilter($name)) { throw $e;
$message = sprintf('The filter "%s" does not exist', $name); }
if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) {
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); if ($filter instanceof Twig_SimpleFilter && $filter->isDeprecated()) {
$message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
if (!is_bool($filter->getDeprecatedVersion())) {
$message .= sprintf(' since version %s', $filter->getDeprecatedVersion());
}
if ($filter->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $filter->getAlternative());
} }
$src = $this->parser->getStream()->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line);
throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename()); @trigger_error($message, E_USER_DEPRECATED);
} }
if ($filter instanceof Twig_SimpleFilter) { if ($filter instanceof Twig_SimpleFilter) {
@ -585,7 +725,9 @@ class Twig_ExpressionParser
// checks that the node only contains "constant" elements // checks that the node only contains "constant" elements
protected function checkConstantExpression(Twig_NodeInterface $node) protected function checkConstantExpression(Twig_NodeInterface $node)
{ {
if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) { if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array
|| $node instanceof Twig_Node_Expression_Unary_Neg || $node instanceof Twig_Node_Expression_Unary_Pos
)) {
return false; return false;
} }
@ -597,15 +739,6 @@ class Twig_ExpressionParser
return true; return true;
} }
private function createArrayFromArguments(Twig_Node $arguments, $line = null)
{
$line = null === $line ? $arguments->getLine() : $line;
$array = new Twig_Node_Expression_Array(array(), $line);
foreach ($arguments as $key => $value) {
$array->addElement($value, new Twig_Node_Expression_Constant($key, $value->getLine()));
}
return $array;
}
} }
class_alias('Twig_ExpressionParser', 'Twig\ExpressionParser', false);

54
inc/lib/Twig/Extension.php

@ -3,91 +3,67 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
abstract class Twig_Extension implements Twig_ExtensionInterface abstract class Twig_Extension implements Twig_ExtensionInterface
{ {
/** /**
* Initializes the runtime environment. * @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_InitRuntimeInterface instead
*
* This is where you can load some file that contains filter functions for instance.
*
* @param Twig_Environment $environment The current Twig_Environment instance
*/ */
public function initRuntime(Twig_Environment $environment) public function initRuntime(Twig_Environment $environment)
{ {
} }
/**
* Returns the token parser instances to add to the existing list.
*
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
*/
public function getTokenParsers() public function getTokenParsers()
{ {
return array(); return array();
} }
/**
* Returns the node visitor instances to add to the existing list.
*
* @return array An array of Twig_NodeVisitorInterface instances
*/
public function getNodeVisitors() public function getNodeVisitors()
{ {
return array(); return array();
} }
/**
* Returns a list of filters to add to the existing list.
*
* @return array An array of filters
*/
public function getFilters() public function getFilters()
{ {
return array(); return array();
} }
/**
* Returns a list of tests to add to the existing list.
*
* @return array An array of tests
*/
public function getTests() public function getTests()
{ {
return array(); return array();
} }
/**
* Returns a list of functions to add to the existing list.
*
* @return array An array of functions
*/
public function getFunctions() public function getFunctions()
{ {
return array(); return array();
} }
/**
* Returns a list of operators to add to the existing list.
*
* @return array An array of operators
*/
public function getOperators() public function getOperators()
{ {
return array(); return array();
} }
/** /**
* Returns a list of global variables to add to the existing list. * @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_GlobalsInterface instead
*
* @return array An array of global variables
*/ */
public function getGlobals() public function getGlobals()
{ {
return array(); return array();
} }
/**
* @deprecated since 1.26 (to be removed in 2.0), not used anymore internally
*/
public function getName()
{
return get_class($this);
}
} }
class_alias('Twig_Extension', 'Twig\Extension\AbstractExtension', false);
class_exists('Twig_Environment');

809
inc/lib/Twig/Extension/Core.php

File diff suppressed because it is too large

22
inc/lib/Twig/Extension/Debug.php

@ -3,18 +3,17 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2011 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
/**
* @final
*/
class Twig_Extension_Debug extends Twig_Extension class Twig_Extension_Debug extends Twig_Extension
{ {
/**
* Returns a list of global functions to add to the existing list.
*
* @return array An array of global functions
*/
public function getFunctions() public function getFunctions()
{ {
// dump is safe if var_dump is overridden by xdebug // dump is safe if var_dump is overridden by xdebug
@ -24,7 +23,7 @@ class Twig_Extension_Debug extends Twig_Extension
// false means that it was not set (and the default is on) or it explicitly enabled // false means that it was not set (and the default is on) or it explicitly enabled
// xdebug.overload_var_dump produces HTML only when html_errors is also enabled // xdebug.overload_var_dump produces HTML only when html_errors is also enabled
&& (false === ini_get('html_errors') || ini_get('html_errors')) && (false === ini_get('html_errors') || ini_get('html_errors'))
|| 'cli' === php_sapi_name() || 'cli' === PHP_SAPI
; ;
return array( return array(
@ -32,11 +31,6 @@ class Twig_Extension_Debug extends Twig_Extension
); );
} }
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName() public function getName()
{ {
return 'debug'; return 'debug';
@ -62,10 +56,12 @@ function twig_var_dump(Twig_Environment $env, $context)
var_dump($vars); var_dump($vars);
} else { } else {
for ($i = 2; $i < $count; $i++) { for ($i = 2; $i < $count; ++$i) {
var_dump(func_get_arg($i)); var_dump(func_get_arg($i));
} }
} }
return ob_get_clean(); return ob_get_clean();
} }
class_alias('Twig_Extension_Debug', 'Twig\Extension\DebugExtension', false);

61
inc/lib/Twig/Extension/Escaper.php

@ -3,45 +3,39 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
/**
* @final
*/
class Twig_Extension_Escaper extends Twig_Extension class Twig_Extension_Escaper extends Twig_Extension
{ {
protected $defaultStrategy; protected $defaultStrategy;
/**
* @param string|false|callable $defaultStrategy An escaping strategy
*
* @see setDefaultStrategy()
*/
public function __construct($defaultStrategy = 'html') public function __construct($defaultStrategy = 'html')
{ {
$this->setDefaultStrategy($defaultStrategy); $this->setDefaultStrategy($defaultStrategy);
} }
/**
* Returns the token parser instances to add to the existing list.
*
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
*/
public function getTokenParsers() public function getTokenParsers()
{ {
return array(new Twig_TokenParser_AutoEscape()); return array(new Twig_TokenParser_AutoEscape());
} }
/**
* Returns the node visitor instances to add to the existing list.
*
* @return array An array of Twig_NodeVisitorInterface instances
*/
public function getNodeVisitors() public function getNodeVisitors()
{ {
return array(new Twig_NodeVisitor_Escaper()); return array(new Twig_NodeVisitor_Escaper());
} }
/**
* Returns a list of filters to add to the existing list.
*
* @return array An array of filters
*/
public function getFilters() public function getFilters()
{ {
return array( return array(
@ -53,43 +47,50 @@ class Twig_Extension_Escaper extends Twig_Extension
* Sets the default strategy to use when not defined by the user. * Sets the default strategy to use when not defined by the user.
* *
* The strategy can be a valid PHP callback that takes the template * The strategy can be a valid PHP callback that takes the template
* "filename" as an argument and returns the strategy to use. * name as an argument and returns the strategy to use.
* *
* @param mixed $defaultStrategy An escaping strategy * @param string|false|callable $defaultStrategy An escaping strategy
*/ */
public function setDefaultStrategy($defaultStrategy) public function setDefaultStrategy($defaultStrategy)
{ {
// for BC // for BC
if (true === $defaultStrategy) { if (true === $defaultStrategy) {
@trigger_error('Using "true" as the default strategy is deprecated since version 1.21. Use "html" instead.', E_USER_DEPRECATED);
$defaultStrategy = 'html'; $defaultStrategy = 'html';
} }
if ('filename' === $defaultStrategy) {
@trigger_error('Using "filename" as the default strategy is deprecated since version 1.27. Use "name" instead.', E_USER_DEPRECATED);
$defaultStrategy = 'name';
}
if ('name' === $defaultStrategy) {
$defaultStrategy = array('Twig_FileExtensionEscapingStrategy', 'guess');
}
$this->defaultStrategy = $defaultStrategy; $this->defaultStrategy = $defaultStrategy;
} }
/** /**
* Gets the default strategy to use when not defined by the user. * Gets the default strategy to use when not defined by the user.
* *
* @param string $filename The template "filename" * @param string $name The template name
* *
* @return string The default strategy to use for the template * @return string|false The default strategy to use for the template
*/ */
public function getDefaultStrategy($filename) public function getDefaultStrategy($name)
{ {
// disable string callables to avoid calling a function named html or js, // disable string callables to avoid calling a function named html or js,
// or any other upcoming escaping strategy // or any other upcoming escaping strategy
if (!is_string($this->defaultStrategy) && is_callable($this->defaultStrategy)) { if (!is_string($this->defaultStrategy) && false !== $this->defaultStrategy) {
return call_user_func($this->defaultStrategy, $filename); return call_user_func($this->defaultStrategy, $name);
} }
return $this->defaultStrategy; return $this->defaultStrategy;
} }
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName() public function getName()
{ {
return 'escaper'; return 'escaper';
@ -100,8 +101,12 @@ class Twig_Extension_Escaper extends Twig_Extension
* Marks a variable as being safe. * Marks a variable as being safe.
* *
* @param string $string A PHP variable * @param string $string A PHP variable
*
* @return string
*/ */
function twig_raw_filter($string) function twig_raw_filter($string)
{ {
return $string; return $string;
} }
class_alias('Twig_Extension_Escaper', 'Twig\Extension\EscaperExtension', false);

24
inc/lib/Twig/Extension/GlobalsInterface.php

@ -0,0 +1,24 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Enables usage of the deprecated Twig_Extension::getGlobals() method.
*
* Explicitly implement this interface if you really need to implement the
* deprecated getGlobals() method in your extensions.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface Twig_Extension_GlobalsInterface
{
}
class_alias('Twig_Extension_GlobalsInterface', 'Twig\Extension\GlobalsInterface', false);

24
inc/lib/Twig/Extension/InitRuntimeInterface.php

@ -0,0 +1,24 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Enables usage of the deprecated Twig_Extension::initRuntime() method.
*
* Explicitly implement this interface if you really need to implement the
* deprecated initRuntime() method in your extensions.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface Twig_Extension_InitRuntimeInterface
{
}
class_alias('Twig_Extension_InitRuntimeInterface', 'Twig\Extension\InitRuntimeInterface', false);

14
inc/lib/Twig/Extension/Optimizer.php

@ -3,11 +3,15 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
/**
* @final
*/
class Twig_Extension_Optimizer extends Twig_Extension class Twig_Extension_Optimizer extends Twig_Extension
{ {
protected $optimizers; protected $optimizers;
@ -17,19 +21,15 @@ class Twig_Extension_Optimizer extends Twig_Extension
$this->optimizers = $optimizers; $this->optimizers = $optimizers;
} }
/**
* {@inheritdoc}
*/
public function getNodeVisitors() public function getNodeVisitors()
{ {
return array(new Twig_NodeVisitor_Optimizer($this->optimizers)); return array(new Twig_NodeVisitor_Optimizer($this->optimizers));
} }
/**
* {@inheritdoc}
*/
public function getName() public function getName()
{ {
return 'optimizer'; return 'optimizer';
} }
} }
class_alias('Twig_Extension_Optimizer', 'Twig\Extension\OptimizerExtension', false);

49
inc/lib/Twig/Extension/Profiler.php

@ -0,0 +1,49 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extension_Profiler extends Twig_Extension
{
private $actives = array();
public function __construct(Twig_Profiler_Profile $profile)
{
$this->actives[] = $profile;
}
public function enter(Twig_Profiler_Profile $profile)
{
$this->actives[0]->addProfile($profile);
array_unshift($this->actives, $profile);
}
public function leave(Twig_Profiler_Profile $profile)
{
$profile->leave();
array_shift($this->actives);
if (1 === count($this->actives)) {
$this->actives[0]->leave();
}
}
public function getNodeVisitors()
{
return array(new Twig_Profiler_NodeVisitor_Profiler(get_class($this)));
}
public function getName()
{
return 'profiler';
}
}
class_alias('Twig_Extension_Profiler', 'Twig\Extension\ProfilerExtension', false);
class_exists('Twig_Profiler_Profile');

27
inc/lib/Twig/Extension/Sandbox.php

@ -3,11 +3,15 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
/**
* @final
*/
class Twig_Extension_Sandbox extends Twig_Extension class Twig_Extension_Sandbox extends Twig_Extension
{ {
protected $sandboxedGlobally; protected $sandboxedGlobally;
@ -16,25 +20,15 @@ class Twig_Extension_Sandbox extends Twig_Extension
public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false) public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false)
{ {
$this->policy = $policy; $this->policy = $policy;
$this->sandboxedGlobally = $sandboxed; $this->sandboxedGlobally = $sandboxed;
} }
/**
* Returns the token parser instances to add to the existing list.
*
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
*/
public function getTokenParsers() public function getTokenParsers()
{ {
return array(new Twig_TokenParser_Sandbox()); return array(new Twig_TokenParser_Sandbox());
} }
/**
* Returns the node visitor instances to add to the existing list.
*
* @return array An array of Twig_NodeVisitorInterface instances
*/
public function getNodeVisitors() public function getNodeVisitors()
{ {
return array(new Twig_NodeVisitor_Sandbox()); return array(new Twig_NodeVisitor_Sandbox());
@ -93,20 +87,17 @@ class Twig_Extension_Sandbox extends Twig_Extension
public function ensureToStringAllowed($obj) public function ensureToStringAllowed($obj)
{ {
if (is_object($obj)) { if ($this->isSandboxed() && is_object($obj)) {
$this->policy->checkMethodAllowed($obj, '__toString'); $this->policy->checkMethodAllowed($obj, '__toString');
} }
return $obj; return $obj;
} }
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName() public function getName()
{ {
return 'sandbox'; return 'sandbox';
} }
} }
class_alias('Twig_Extension_Sandbox', 'Twig\Extension\SandboxExtension', false);

45
inc/lib/Twig/Extension/Staging.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2012 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -15,6 +15,8 @@
* This class is used by Twig_Environment as a staging area and must not be used directly. * This class is used by Twig_Environment as a staging area and must not be used directly.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/ */
class Twig_Extension_Staging extends Twig_Extension class Twig_Extension_Staging extends Twig_Extension
{ {
@ -27,12 +29,13 @@ class Twig_Extension_Staging extends Twig_Extension
public function addFunction($name, $function) public function addFunction($name, $function)
{ {
if (isset($this->functions[$name])) {
@trigger_error(sprintf('Overriding function "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
}
$this->functions[$name] = $function; $this->functions[$name] = $function;
} }
/**
* {@inheritdoc}
*/
public function getFunctions() public function getFunctions()
{ {
return $this->functions; return $this->functions;
@ -40,12 +43,13 @@ class Twig_Extension_Staging extends Twig_Extension
public function addFilter($name, $filter) public function addFilter($name, $filter)
{ {
if (isset($this->filters[$name])) {
@trigger_error(sprintf('Overriding filter "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
}
$this->filters[$name] = $filter; $this->filters[$name] = $filter;
} }
/**
* {@inheritdoc}
*/
public function getFilters() public function getFilters()
{ {
return $this->filters; return $this->filters;
@ -56,9 +60,6 @@ class Twig_Extension_Staging extends Twig_Extension
$this->visitors[] = $visitor; $this->visitors[] = $visitor;
} }
/**
* {@inheritdoc}
*/
public function getNodeVisitors() public function getNodeVisitors()
{ {
return $this->visitors; return $this->visitors;
@ -66,12 +67,13 @@ class Twig_Extension_Staging extends Twig_Extension
public function addTokenParser(Twig_TokenParserInterface $parser) public function addTokenParser(Twig_TokenParserInterface $parser)
{ {
$this->tokenParsers[] = $parser; if (isset($this->tokenParsers[$parser->getTag()])) {
@trigger_error(sprintf('Overriding tag "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $parser->getTag()), E_USER_DEPRECATED);
}
$this->tokenParsers[$parser->getTag()] = $parser;
} }
/**
* {@inheritdoc}
*/
public function getTokenParsers() public function getTokenParsers()
{ {
return $this->tokenParsers; return $this->tokenParsers;
@ -82,9 +84,6 @@ class Twig_Extension_Staging extends Twig_Extension
$this->globals[$name] = $value; $this->globals[$name] = $value;
} }
/**
* {@inheritdoc}
*/
public function getGlobals() public function getGlobals()
{ {
return $this->globals; return $this->globals;
@ -92,22 +91,22 @@ class Twig_Extension_Staging extends Twig_Extension
public function addTest($name, $test) public function addTest($name, $test)
{ {
if (isset($this->tests[$name])) {
@trigger_error(sprintf('Overriding test "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
}
$this->tests[$name] = $test; $this->tests[$name] = $test;
} }
/**
* {@inheritdoc}
*/
public function getTests() public function getTests()
{ {
return $this->tests; return $this->tests;
} }
/**
* {@inheritdoc}
*/
public function getName() public function getName()
{ {
return 'staging'; return 'staging';
} }
} }
class_alias('Twig_Extension_Staging', 'Twig\Extension\StagingExtension', false);

37
inc/lib/Twig/Extension/StringLoader.php

@ -3,16 +3,17 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2012 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
/**
* @final
*/
class Twig_Extension_StringLoader extends Twig_Extension class Twig_Extension_StringLoader extends Twig_Extension
{ {
/**
* {@inheritdoc}
*/
public function getFunctions() public function getFunctions()
{ {
return array( return array(
@ -20,9 +21,6 @@ class Twig_Extension_StringLoader extends Twig_Extension
); );
} }
/**
* {@inheritdoc}
*/
public function getName() public function getName()
{ {
return 'string_loader'; return 'string_loader';
@ -37,28 +35,13 @@ class Twig_Extension_StringLoader extends Twig_Extension
* </pre> * </pre>
* *
* @param Twig_Environment $env A Twig_Environment instance * @param Twig_Environment $env A Twig_Environment instance
* @param string $template A template as a string * @param string $template A template as a string or object implementing __toString()
* *
* @return Twig_Template A Twig_Template instance * @return Twig_Template
*/ */
function twig_template_from_string(Twig_Environment $env, $template) function twig_template_from_string(Twig_Environment $env, $template)
{ {
$name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false)); return $env->createTemplate((string) $template);
$loader = new Twig_Loader_Chain(array(
new Twig_Loader_Array(array($name => $template)),
$current = $env->getLoader(),
));
$env->setLoader($loader);
try {
$template = $env->loadTemplate($name);
} catch (Exception $e) {
$env->setLoader($current);
throw $e;
}
$env->setLoader($current);
return $template;
} }
class_alias('Twig_Extension_StringLoader', 'Twig\Extension\StringLoaderExtension', false);

23
inc/lib/Twig/ExtensionInterface.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -21,49 +21,49 @@ interface Twig_ExtensionInterface
* *
* This is where you can load some file that contains filter functions for instance. * This is where you can load some file that contains filter functions for instance.
* *
* @param Twig_Environment $environment The current Twig_Environment instance * @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_InitRuntimeInterface instead
*/ */
public function initRuntime(Twig_Environment $environment); public function initRuntime(Twig_Environment $environment);
/** /**
* Returns the token parser instances to add to the existing list. * Returns the token parser instances to add to the existing list.
* *
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances * @return Twig_TokenParserInterface[]
*/ */
public function getTokenParsers(); public function getTokenParsers();
/** /**
* Returns the node visitor instances to add to the existing list. * Returns the node visitor instances to add to the existing list.
* *
* @return array An array of Twig_NodeVisitorInterface instances * @return Twig_NodeVisitorInterface[]
*/ */
public function getNodeVisitors(); public function getNodeVisitors();
/** /**
* Returns a list of filters to add to the existing list. * Returns a list of filters to add to the existing list.
* *
* @return array An array of filters * @return Twig_SimpleFilter[]
*/ */
public function getFilters(); public function getFilters();
/** /**
* Returns a list of tests to add to the existing list. * Returns a list of tests to add to the existing list.
* *
* @return array An array of tests * @return Twig_SimpleTest[]
*/ */
public function getTests(); public function getTests();
/** /**
* Returns a list of functions to add to the existing list. * Returns a list of functions to add to the existing list.
* *
* @return array An array of functions * @return Twig_SimpleFunction[]
*/ */
public function getFunctions(); public function getFunctions();
/** /**
* Returns a list of operators to add to the existing list. * Returns a list of operators to add to the existing list.
* *
* @return array An array of operators * @return array<array> First array of unary operators, second array of binary operators
*/ */
public function getOperators(); public function getOperators();
@ -71,6 +71,8 @@ interface Twig_ExtensionInterface
* Returns a list of global variables to add to the existing list. * Returns a list of global variables to add to the existing list.
* *
* @return array An array of global variables * @return array An array of global variables
*
* @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_GlobalsInterface instead
*/ */
public function getGlobals(); public function getGlobals();
@ -78,6 +80,11 @@ interface Twig_ExtensionInterface
* Returns the name of the extension. * Returns the name of the extension.
* *
* @return string The extension name * @return string The extension name
*
* @deprecated since 1.26 (to be removed in 2.0), not used anymore internally
*/ */
public function getName(); public function getName();
} }
class_alias('Twig_ExtensionInterface', 'Twig\Extension\ExtensionInterface', false);
class_exists('Twig_Environment');

39
inc/lib/Twig/FactoryRuntimeLoader.php

@ -0,0 +1,39 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Lazy loads the runtime implementations for a Twig element.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class Twig_FactoryRuntimeLoader implements Twig_RuntimeLoaderInterface
{
private $map;
/**
* @param array $map An array where keys are class names and values factory callables
*/
public function __construct($map = array())
{
$this->map = $map;
}
public function load($class)
{
if (isset($this->map[$class])) {
$runtimeFactory = $this->map[$class];
return $runtimeFactory();
}
}
}
class_alias('Twig_FactoryRuntimeLoader', 'Twig\RuntimeLoader\FactoryRuntimeLoader', false);

60
inc/lib/Twig/FileExtensionEscapingStrategy.php

@ -0,0 +1,60 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Default autoescaping strategy based on file names.
*
* This strategy sets the HTML as the default autoescaping strategy,
* but changes it based on the template name.
*
* Note that there is no runtime performance impact as the
* default autoescaping strategy is set at compilation time.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_FileExtensionEscapingStrategy
{
/**
* Guesses the best autoescaping strategy based on the file name.
*
* @param string $name The template name
*
* @return string|false The escaping strategy name to use or false to disable
*/
public static function guess($name)
{
if (in_array(substr($name, -1), array('/', '\\'))) {
return 'html'; // return html for directories
}
if ('.twig' === substr($name, -5)) {
$name = substr($name, 0, -5);
}
$extension = pathinfo($name, PATHINFO_EXTENSION);
switch ($extension) {
case 'js':
return 'js';
case 'css':
return 'css';
case 'txt':
return false;
default:
return 'html';
}
}
}
class_alias('Twig_FileExtensionEscapingStrategy', 'Twig\FileExtensionEscapingStrategy', false);

13
inc/lib/Twig/Filter.php

@ -3,18 +3,21 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
@trigger_error('The Twig_Filter class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFilter instead.', E_USER_DEPRECATED);
/** /**
* Represents a template filter. * Represents a template filter.
* *
* Use Twig_SimpleFilter instead. * Use Twig_SimpleFilter instead.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0) * @deprecated since 1.12 (to be removed in 2.0)
*/ */
abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface
@ -26,10 +29,10 @@ abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableI
{ {
$this->options = array_merge(array( $this->options = array_merge(array(
'needs_environment' => false, 'needs_environment' => false,
'needs_context' => false, 'needs_context' => false,
'pre_escape' => null, 'pre_escape' => null,
'preserves_safety' => null, 'preserves_safety' => null,
'callable' => null, 'callable' => null,
), $options); ), $options);
} }

5
inc/lib/Twig/Filter/Function.php

@ -3,18 +3,21 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
@trigger_error('The Twig_Filter_Function class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFilter instead.', E_USER_DEPRECATED);
/** /**
* Represents a function template filter. * Represents a function template filter.
* *
* Use Twig_SimpleFilter instead. * Use Twig_SimpleFilter instead.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0) * @deprecated since 1.12 (to be removed in 2.0)
*/ */
class Twig_Filter_Function extends Twig_Filter class Twig_Filter_Function extends Twig_Filter

7
inc/lib/Twig/Filter/Method.php

@ -3,18 +3,21 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
@trigger_error('The Twig_Filter_Method class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFilter instead.', E_USER_DEPRECATED);
/** /**
* Represents a method template filter. * Represents a method template filter.
* *
* Use Twig_SimpleFilter instead. * Use Twig_SimpleFilter instead.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0) * @deprecated since 1.12 (to be removed in 2.0)
*/ */
class Twig_Filter_Method extends Twig_Filter class Twig_Filter_Method extends Twig_Filter
@ -34,6 +37,6 @@ class Twig_Filter_Method extends Twig_Filter
public function compile() public function compile()
{ {
return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); return sprintf('$this->env->getExtension(\'%s\')->%s', get_class($this->extension), $this->method);
} }
} }

5
inc/lib/Twig/Filter/Node.php

@ -3,18 +3,21 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2011 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
@trigger_error('The Twig_Filter_Node class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFilter instead.', E_USER_DEPRECATED);
/** /**
* Represents a template filter as a node. * Represents a template filter as a node.
* *
* Use Twig_SimpleFilter instead. * Use Twig_SimpleFilter instead.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0) * @deprecated since 1.12 (to be removed in 2.0)
*/ */
class Twig_Filter_Node extends Twig_Filter class Twig_Filter_Node extends Twig_Filter

3
inc/lib/Twig/FilterCallableInterface.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2012 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -15,6 +15,7 @@
* Use Twig_SimpleFilter instead. * Use Twig_SimpleFilter instead.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0) * @deprecated since 1.12 (to be removed in 2.0)
*/ */
interface Twig_FilterCallableInterface interface Twig_FilterCallableInterface

3
inc/lib/Twig/FilterInterface.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -15,6 +15,7 @@
* Use Twig_SimpleFilter instead. * Use Twig_SimpleFilter instead.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0) * @deprecated since 1.12 (to be removed in 2.0)
*/ */
interface Twig_FilterInterface interface Twig_FilterInterface

9
inc/lib/Twig/Function.php

@ -3,18 +3,21 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
@trigger_error('The Twig_Function class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFunction instead.', E_USER_DEPRECATED);
/** /**
* Represents a template function. * Represents a template function.
* *
* Use Twig_SimpleFunction instead. * Use Twig_SimpleFunction instead.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0) * @deprecated since 1.12 (to be removed in 2.0)
*/ */
abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface
@ -26,8 +29,8 @@ abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCal
{ {
$this->options = array_merge(array( $this->options = array_merge(array(
'needs_environment' => false, 'needs_environment' => false,
'needs_context' => false, 'needs_context' => false,
'callable' => null, 'callable' => null,
), $options); ), $options);
} }

7
inc/lib/Twig/Function/Function.php

@ -3,19 +3,22 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2010 Arnaud Le Blanc * (c) Arnaud Le Blanc
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
@trigger_error('The Twig_Function_Function class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFunction instead.', E_USER_DEPRECATED);
/** /**
* Represents a function template function. * Represents a function template function.
* *
* Use Twig_SimpleFunction instead. * Use Twig_SimpleFunction instead.
* *
* @author Arnaud Le Blanc <arnaud.lb@gmail.com> * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @deprecated since 1.12 (to be removed in 2.0) * @deprecated since 1.12 (to be removed in 2.0)
*/ */
class Twig_Function_Function extends Twig_Function class Twig_Function_Function extends Twig_Function

9
inc/lib/Twig/Function/Method.php

@ -3,19 +3,22 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2010 Arnaud Le Blanc * (c) Arnaud Le Blanc
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
@trigger_error('The Twig_Function_Method class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFunction instead.', E_USER_DEPRECATED);
/** /**
* Represents a method template function. * Represents a method template function.
* *
* Use Twig_SimpleFunction instead. * Use Twig_SimpleFunction instead.
* *
* @author Arnaud Le Blanc <arnaud.lb@gmail.com> * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @deprecated since 1.12 (to be removed in 2.0) * @deprecated since 1.12 (to be removed in 2.0)
*/ */
class Twig_Function_Method extends Twig_Function class Twig_Function_Method extends Twig_Function
@ -35,6 +38,6 @@ class Twig_Function_Method extends Twig_Function
public function compile() public function compile()
{ {
return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); return sprintf('$this->env->getExtension(\'%s\')->%s', get_class($this->extension), $this->method);
} }
} }

5
inc/lib/Twig/Function/Node.php

@ -3,18 +3,21 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2011 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
@trigger_error('The Twig_Function_Node class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFunction instead.', E_USER_DEPRECATED);
/** /**
* Represents a template function as a node. * Represents a template function as a node.
* *
* Use Twig_SimpleFunction instead. * Use Twig_SimpleFunction instead.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0) * @deprecated since 1.12 (to be removed in 2.0)
*/ */
class Twig_Function_Node extends Twig_Function class Twig_Function_Node extends Twig_Function

3
inc/lib/Twig/FunctionCallableInterface.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2012 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -15,6 +15,7 @@
* Use Twig_SimpleFunction instead. * Use Twig_SimpleFunction instead.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0) * @deprecated since 1.12 (to be removed in 2.0)
*/ */
interface Twig_FunctionCallableInterface interface Twig_FunctionCallableInterface

5
inc/lib/Twig/FunctionInterface.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* (c) 2010 Arnaud Le Blanc * (c) Arnaud Le Blanc
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -16,6 +16,7 @@
* Use Twig_SimpleFunction instead. * Use Twig_SimpleFunction instead.
* *
* @author Arnaud Le Blanc <arnaud.lb@gmail.com> * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @deprecated since 1.12 (to be removed in 2.0) * @deprecated since 1.12 (to be removed in 2.0)
*/ */
interface Twig_FunctionInterface interface Twig_FunctionInterface

127
inc/lib/Twig/Lexer.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -26,6 +26,7 @@ class Twig_Lexer implements Twig_LexerInterface
protected $states; protected $states;
protected $brackets; protected $brackets;
protected $env; protected $env;
// to be renamed to $name in 2.0 (where it is private)
protected $filename; protected $filename;
protected $options; protected $options;
protected $regexes; protected $regexes;
@ -33,62 +34,69 @@ class Twig_Lexer implements Twig_LexerInterface
protected $positions; protected $positions;
protected $currentVarBlockLine; protected $currentVarBlockLine;
const STATE_DATA = 0; private $source;
const STATE_BLOCK = 1;
const STATE_VAR = 2;
const STATE_STRING = 3;
const STATE_INTERPOLATION = 4;
const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A'; const STATE_DATA = 0;
const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A'; const STATE_BLOCK = 1;
const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As'; const STATE_VAR = 2;
const STATE_STRING = 3;
const STATE_INTERPOLATION = 4;
const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A';
const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
const REGEX_DQ_STRING_DELIM = '/"/A'; const REGEX_DQ_STRING_DELIM = '/"/A';
const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As'; const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
const PUNCTUATION = '()[]{}?:.,|'; const PUNCTUATION = '()[]{}?:.,|';
public function __construct(Twig_Environment $env, array $options = array()) public function __construct(Twig_Environment $env, array $options = array())
{ {
$this->env = $env; $this->env = $env;
$this->options = array_merge(array( $this->options = array_merge(array(
'tag_comment' => array('{#', '#}'), 'tag_comment' => array('{#', '#}'),
'tag_block' => array('{%', '%}'), 'tag_block' => array('{%', '%}'),
'tag_variable' => array('{{', '}}'), 'tag_variable' => array('{{', '}}'),
'whitespace_trim' => '-', 'whitespace_trim' => '-',
'interpolation' => array('#{', '}'), 'interpolation' => array('#{', '}'),
), $options); ), $options);
$this->regexes = array( $this->regexes = array(
'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A', 'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A',
'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A', 'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A',
'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s', 'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s',
'operator' => $this->getOperatorRegex(), 'operator' => $this->getOperatorRegex(),
'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s', 'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s',
'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As', 'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As',
'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As', 'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As',
'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s', 'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s',
'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A', 'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A',
'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A', 'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A',
); );
} }
/** public function tokenize($code, $name = null)
* Tokenizes a source code.
*
* @param string $code The source code
* @param string $filename A unique identifier for the source code
*
* @return Twig_TokenStream A token stream instance
*/
public function tokenize($code, $filename = null)
{ {
if (!$code instanceof Twig_Source) {
@trigger_error(sprintf('Passing a string as the $code argument of %s() is deprecated since version 1.27 and will be removed in 2.0. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED);
$this->source = new Twig_Source($code, $name);
} else {
$this->source = $code;
}
if (((int) ini_get('mbstring.func_overload')) & 2) {
@trigger_error('Support for having "mbstring.func_overload" different from 0 is deprecated version 1.29 and will be removed in 2.0.', E_USER_DEPRECATED);
}
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) { if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
$mbEncoding = mb_internal_encoding(); $mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII'); mb_internal_encoding('ASCII');
} else {
$mbEncoding = null;
} }
$this->code = str_replace(array("\r\n", "\r"), "\n", $code); $this->code = str_replace(array("\r\n", "\r"), "\n", $this->source->getCode());
$this->filename = $filename; $this->filename = $this->source->getName();
$this->cursor = 0; $this->cursor = 0;
$this->lineno = 1; $this->lineno = 1;
$this->end = strlen($this->code); $this->end = strlen($this->code);
@ -132,14 +140,14 @@ class Twig_Lexer implements Twig_LexerInterface
if (!empty($this->brackets)) { if (!empty($this->brackets)) {
list($expect, $lineno) = array_pop($this->brackets); list($expect, $lineno) = array_pop($this->brackets);
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
} }
if (isset($mbEncoding)) { if ($mbEncoding) {
mb_internal_encoding($mbEncoding); mb_internal_encoding($mbEncoding);
} }
return new Twig_TokenStream($this->tokens, $this->filename); return new Twig_TokenStream($this->tokens, $this->source);
} }
protected function lexData() protected function lexData()
@ -227,13 +235,13 @@ class Twig_Lexer implements Twig_LexerInterface
$this->moveCursor($match[0]); $this->moveCursor($match[0]);
if ($this->cursor >= $this->end) { if ($this->cursor >= $this->end) {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename); throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', self::STATE_BLOCK === $this->state ? 'block' : 'variable'), $this->currentVarBlockLine, $this->source);
} }
} }
// operators // operators
if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) { if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::OPERATOR_TYPE, $match[0]); $this->pushToken(Twig_Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0]));
$this->moveCursor($match[0]); $this->moveCursor($match[0]);
} }
// names // names
@ -259,12 +267,12 @@ class Twig_Lexer implements Twig_LexerInterface
// closing bracket // closing bracket
elseif (false !== strpos(')]}', $this->code[$this->cursor])) { elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
if (empty($this->brackets)) { if (empty($this->brackets)) {
throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename); throw new Twig_Error_Syntax(sprintf('Unexpected "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
} }
list($expect, $lineno) = array_pop($this->brackets); list($expect, $lineno) = array_pop($this->brackets);
if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) { if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
} }
} }
@ -284,14 +292,18 @@ class Twig_Lexer implements Twig_LexerInterface
} }
// unlexable // unlexable
else { else {
throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename); throw new Twig_Error_Syntax(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
} }
} }
protected function lexRawData($tag) protected function lexRawData($tag)
{ {
if ('raw' === $tag) {
@trigger_error(sprintf('Twig Tag "raw" is deprecated since version 1.21. Use "verbatim" instead in %s at line %d.', $this->filename, $this->lineno), E_USER_DEPRECATED);
}
if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename); throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block.', $tag), $this->lineno, $this->source);
} }
$text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor); $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
@ -307,7 +319,7 @@ class Twig_Lexer implements Twig_LexerInterface
protected function lexComment() protected function lexComment()
{ {
if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename); throw new Twig_Error_Syntax('Unclosed comment.', $this->lineno, $this->source);
} }
$this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]); $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
@ -320,20 +332,20 @@ class Twig_Lexer implements Twig_LexerInterface
$this->pushToken(Twig_Token::INTERPOLATION_START_TYPE); $this->pushToken(Twig_Token::INTERPOLATION_START_TYPE);
$this->moveCursor($match[0]); $this->moveCursor($match[0]);
$this->pushState(self::STATE_INTERPOLATION); $this->pushState(self::STATE_INTERPOLATION);
} elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) { } elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) {
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0])); $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0]));
$this->moveCursor($match[0]); $this->moveCursor($match[0]);
} elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) { } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
list($expect, $lineno) = array_pop($this->brackets); list($expect, $lineno) = array_pop($this->brackets);
if ($this->code[$this->cursor] != '"') { if ('"' != $this->code[$this->cursor]) {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
} }
$this->popState(); $this->popState();
++$this->cursor; ++$this->cursor;
} else {
// unlexable
throw new Twig_Error_Syntax(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
} }
} }
@ -382,10 +394,15 @@ class Twig_Lexer implements Twig_LexerInterface
// an operator that ends with a character must be followed by // an operator that ends with a character must be followed by
// a whitespace or a parenthesis // a whitespace or a parenthesis
if (ctype_alpha($operator[$length - 1])) { if (ctype_alpha($operator[$length - 1])) {
$regex[] = preg_quote($operator, '/').'(?=[\s()])'; $r = preg_quote($operator, '/').'(?=[\s()])';
} else { } else {
$regex[] = preg_quote($operator, '/'); $r = preg_quote($operator, '/');
} }
// an operator with a space can be any amount of whitespaces
$r = preg_replace('/\s+/', '\s+', $r);
$regex[] = $r;
} }
return '/'.implode('|', $regex).'/A'; return '/'.implode('|', $regex).'/A';
@ -400,9 +417,11 @@ class Twig_Lexer implements Twig_LexerInterface
protected function popState() protected function popState()
{ {
if (0 === count($this->states)) { if (0 === count($this->states)) {
throw new Exception('Cannot pop state without a previous state'); throw new Exception('Cannot pop state without a previous state.');
} }
$this->state = array_pop($this->states); $this->state = array_pop($this->states);
} }
} }
class_alias('Twig_Lexer', 'Twig\Lexer', false);

15
inc/lib/Twig/LexerInterface.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -13,17 +13,20 @@
* Interface implemented by lexer classes. * Interface implemented by lexer classes.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0) *
* @deprecated since 1.12 (to be removed in 3.0)
*/ */
interface Twig_LexerInterface interface Twig_LexerInterface
{ {
/** /**
* Tokenizes a source code. * Tokenizes a source code.
* *
* @param string $code The source code * @param string|Twig_Source $code The source code
* @param string $filename A unique identifier for the source code * @param string $name A unique identifier for the source code
*
* @return Twig_TokenStream
* *
* @return Twig_TokenStream A token stream instance * @throws Twig_Error_Syntax When the code is syntactically wrong
*/ */
public function tokenize($code, $filename = null); public function tokenize($code, $name = null);
} }

42
inc/lib/Twig/Loader/Array.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -17,20 +17,20 @@
* source code of the template). If you don't want to see your cache grows out of * source code of the template). If you don't want to see your cache grows out of
* control, you need to take care of clearing the old cache file by yourself. * control, you need to take care of clearing the old cache file by yourself.
* *
* This loader should only be used for unit testing.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*/ */
class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
{ {
protected $templates = array(); protected $templates = array();
/** /**
* Constructor.
*
* @param array $templates An array of templates (keys are the names, and values are the source code) * @param array $templates An array of templates (keys are the names, and values are the source code)
*
* @see Twig_Loader
*/ */
public function __construct(array $templates) public function __construct(array $templates = array())
{ {
$this->templates = $templates; $this->templates = $templates;
} }
@ -46,11 +46,10 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
$this->templates[(string) $name] = $template; $this->templates[(string) $name] = $template;
} }
/**
* {@inheritdoc}
*/
public function getSource($name) public function getSource($name)
{ {
@trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
$name = (string) $name; $name = (string) $name;
if (!isset($this->templates[$name])) { if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
@ -59,17 +58,21 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
return $this->templates[$name]; return $this->templates[$name];
} }
/** public function getSourceContext($name)
* {@inheritdoc} {
*/ $name = (string) $name;
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return new Twig_Source($this->templates[$name], $name);
}
public function exists($name) public function exists($name)
{ {
return isset($this->templates[(string) $name]); return isset($this->templates[(string) $name]);
} }
/**
* {@inheritdoc}
*/
public function getCacheKey($name) public function getCacheKey($name)
{ {
$name = (string) $name; $name = (string) $name;
@ -77,12 +80,9 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
} }
return $this->templates[$name]; return $name.':'.$this->templates[$name];
} }
/**
* {@inheritdoc}
*/
public function isFresh($name, $time) public function isFresh($name, $time)
{ {
$name = (string) $name; $name = (string) $name;
@ -93,3 +93,5 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
return true; return true;
} }
} }
class_alias('Twig_Loader_Array', 'Twig\Loader\ArrayLoader', false);

65
inc/lib/Twig/Loader/Chain.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2011 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -12,17 +12,17 @@
/** /**
* Loads templates from other loaders. * Loads templates from other loaders.
* *
* @final
*
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*/ */
class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
{ {
private $hasSourceCache = array(); private $hasSourceCache = array();
protected $loaders = array(); protected $loaders = array();
/** /**
* Constructor. * @param Twig_LoaderInterface[] $loaders
*
* @param Twig_LoaderInterface[] $loaders An array of loader instances
*/ */
public function __construct(array $loaders = array()) public function __construct(array $loaders = array())
{ {
@ -31,22 +31,16 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
} }
} }
/**
* Adds a loader instance.
*
* @param Twig_LoaderInterface $loader A Loader instance
*/
public function addLoader(Twig_LoaderInterface $loader) public function addLoader(Twig_LoaderInterface $loader)
{ {
$this->loaders[] = $loader; $this->loaders[] = $loader;
$this->hasSourceCache = array(); $this->hasSourceCache = array();
} }
/**
* {@inheritdoc}
*/
public function getSource($name) public function getSource($name)
{ {
@trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
$exceptions = array(); $exceptions = array();
foreach ($this->loaders as $loader) { foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
@ -60,12 +54,31 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
} }
} }
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions))); throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
public function getSourceContext($name)
{
$exceptions = array();
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
continue;
}
try {
if ($loader instanceof Twig_SourceContextLoaderInterface) {
return $loader->getSourceContext($name);
}
return new Twig_Source($loader->getSource($name), $name);
} catch (Twig_Error_Loader $e) {
$exceptions[] = $e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
} }
/**
* {@inheritdoc}
*/
public function exists($name) public function exists($name)
{ {
$name = (string) $name; $name = (string) $name;
@ -84,7 +97,11 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
} }
try { try {
$loader->getSource($name); if ($loader instanceof Twig_SourceContextLoaderInterface) {
$loader->getSourceContext($name);
} else {
$loader->getSource($name);
}
return $this->hasSourceCache[$name] = true; return $this->hasSourceCache[$name] = true;
} catch (Twig_Error_Loader $e) { } catch (Twig_Error_Loader $e) {
@ -94,9 +111,6 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
return $this->hasSourceCache[$name] = false; return $this->hasSourceCache[$name] = false;
} }
/**
* {@inheritdoc}
*/
public function getCacheKey($name) public function getCacheKey($name)
{ {
$exceptions = array(); $exceptions = array();
@ -112,12 +126,9 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
} }
} }
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions))); throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
} }
/**
* {@inheritdoc}
*/
public function isFresh($name, $time) public function isFresh($name, $time)
{ {
$exceptions = array(); $exceptions = array();
@ -133,6 +144,8 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
} }
} }
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions))); throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
} }
} }
class_alias('Twig_Loader_Chain', 'Twig\Loader\ChainLoader', false);

158
inc/lib/Twig/Loader/Filesystem.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -14,21 +14,28 @@
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*/ */
class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
{ {
/** Identifier of the main namespace. */ /** Identifier of the main namespace. */
const MAIN_NAMESPACE = '__main__'; const MAIN_NAMESPACE = '__main__';
protected $paths = array(); protected $paths = array();
protected $cache = array(); protected $cache = array();
protected $errorCache = array();
private $rootPath;
/** /**
* Constructor. * @param string|array $paths A path or an array of paths where to look for templates
* * @param string|null $rootPath The root path common to all relative paths (null for getcwd())
* @param string|array $paths A path or an array of paths where to look for templates
*/ */
public function __construct($paths = array()) public function __construct($paths = array(), $rootPath = null)
{ {
$this->rootPath = (null === $rootPath ? getcwd() : $rootPath).DIRECTORY_SEPARATOR;
if (false !== $realPath = realpath($rootPath)) {
$this->rootPath = $realPath.DIRECTORY_SEPARATOR;
}
if ($paths) { if ($paths) {
$this->setPaths($paths); $this->setPaths($paths);
} }
@ -80,17 +87,18 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
* Adds a path where templates are stored. * Adds a path where templates are stored.
* *
* @param string $path A path where to look for templates * @param string $path A path where to look for templates
* @param string $namespace A path name * @param string $namespace A path namespace
* *
* @throws Twig_Error_Loader * @throws Twig_Error_Loader
*/ */
public function addPath($path, $namespace = self::MAIN_NAMESPACE) public function addPath($path, $namespace = self::MAIN_NAMESPACE)
{ {
// invalidate the cache // invalidate the cache
$this->cache = array(); $this->cache = $this->errorCache = array();
if (!is_dir($path)) { $checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path)); if (!is_dir($checkPath)) {
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
} }
$this->paths[$namespace][] = rtrim($path, '/\\'); $this->paths[$namespace][] = rtrim($path, '/\\');
@ -100,17 +108,18 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
* Prepends a path where templates are stored. * Prepends a path where templates are stored.
* *
* @param string $path A path where to look for templates * @param string $path A path where to look for templates
* @param string $namespace A path name * @param string $namespace A path namespace
* *
* @throws Twig_Error_Loader * @throws Twig_Error_Loader
*/ */
public function prependPath($path, $namespace = self::MAIN_NAMESPACE) public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
{ {
// invalidate the cache // invalidate the cache
$this->cache = array(); $this->cache = $this->errorCache = array();
if (!is_dir($path)) { $checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path)); if (!is_dir($checkPath)) {
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
} }
$path = rtrim($path, '/\\'); $path = rtrim($path, '/\\');
@ -122,84 +131,126 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
} }
} }
/**
* {@inheritdoc}
*/
public function getSource($name) public function getSource($name)
{ {
@trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
return file_get_contents($this->findTemplate($name)); return file_get_contents($this->findTemplate($name));
} }
/** public function getSourceContext($name)
* {@inheritdoc} {
*/ $path = $this->findTemplate($name);
return new Twig_Source(file_get_contents($path), $name, $path);
}
public function getCacheKey($name) public function getCacheKey($name)
{ {
return $this->findTemplate($name); $path = $this->findTemplate($name);
$len = strlen($this->rootPath);
if (0 === strncmp($this->rootPath, $path, $len)) {
return substr($path, $len);
}
return $path;
} }
/**
* {@inheritdoc}
*/
public function exists($name) public function exists($name)
{ {
$name = (string) $name; $name = $this->normalizeName($name);
if (isset($this->cache[$name])) { if (isset($this->cache[$name])) {
return true; return true;
} }
try { try {
$this->findTemplate($name); return false !== $this->findTemplate($name, false);
return true;
} catch (Twig_Error_Loader $exception) { } catch (Twig_Error_Loader $exception) {
@trigger_error(sprintf('In %s::findTemplate(), you must accept a second argument that when set to "false" returns "false" instead of throwing an exception. Not supporting this argument is deprecated since version 1.27.', get_class($this)), E_USER_DEPRECATED);
return false; return false;
} }
} }
/**
* {@inheritdoc}
*/
public function isFresh($name, $time) public function isFresh($name, $time)
{ {
return filemtime($this->findTemplate($name)) <= $time; return filemtime($this->findTemplate($name)) < $time;
} }
protected function findTemplate($name) protected function findTemplate($name)
{ {
$name = (string) $name; $throw = func_num_args() > 1 ? func_get_arg(1) : true;
$name = $this->normalizeName($name);
// normalize name
$name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/'));
if (isset($this->cache[$name])) { if (isset($this->cache[$name])) {
return $this->cache[$name]; return $this->cache[$name];
} }
$this->validateName($name); if (isset($this->errorCache[$name])) {
if (!$throw) {
$namespace = self::MAIN_NAMESPACE; return false;
$shortname = $name;
if (isset($name[0]) && '@' == $name[0]) {
if (false === $pos = strpos($name, '/')) {
throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
} }
$namespace = substr($name, 1, $pos - 1); throw new Twig_Error_Loader($this->errorCache[$name]);
$shortname = substr($name, $pos + 1);
} }
$this->validateName($name);
list($namespace, $shortname) = $this->parseName($name);
if (!isset($this->paths[$namespace])) { if (!isset($this->paths[$namespace])) {
throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace)); $this->errorCache[$name] = sprintf('There are no registered paths for namespace "%s".', $namespace);
if (!$throw) {
return false;
}
throw new Twig_Error_Loader($this->errorCache[$name]);
} }
foreach ($this->paths[$namespace] as $path) { foreach ($this->paths[$namespace] as $path) {
if (!$this->isAbsolutePath($path)) {
$path = $this->rootPath.'/'.$path;
}
if (is_file($path.'/'.$shortname)) { if (is_file($path.'/'.$shortname)) {
if (false !== $realpath = realpath($path.'/'.$shortname)) {
return $this->cache[$name] = $realpath;
}
return $this->cache[$name] = $path.'/'.$shortname; return $this->cache[$name] = $path.'/'.$shortname;
} }
} }
throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]))); $this->errorCache[$name] = sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]));
if (!$throw) {
return false;
}
throw new Twig_Error_Loader($this->errorCache[$name]);
}
protected function parseName($name, $default = self::MAIN_NAMESPACE)
{
if (isset($name[0]) && '@' == $name[0]) {
if (false === $pos = strpos($name, '/')) {
throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
}
$namespace = substr($name, 1, $pos - 1);
$shortname = substr($name, $pos + 1);
return array($namespace, $shortname);
}
return array($default, $name);
}
protected function normalizeName($name)
{
return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name));
} }
protected function validateName($name) protected function validateName($name)
@ -223,4 +274,17 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
} }
} }
} }
private function isAbsolutePath($file)
{
return strspn($file, '/\\', 0, 1)
|| (strlen($file) > 3 && ctype_alpha($file[0])
&& ':' === substr($file, 1, 1)
&& strspn($file, '/\\', 2, 1)
)
|| null !== parse_url($file, PHP_URL_SCHEME)
;
}
} }
class_alias('Twig_Loader_Filesystem', 'Twig\Loader\FilesystemLoader', false);

33
inc/lib/Twig/Loader/String.php

@ -3,55 +3,54 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
@trigger_error('The Twig_Loader_String class is deprecated since version 1.18.1 and will be removed in 2.0. Use Twig_Loader_Array instead or Twig_Environment::createTemplate().', E_USER_DEPRECATED);
/** /**
* Loads a template from a string. * Loads a template from a string.
* *
* This loader should only be used for unit testing as it has many limitations * This loader should NEVER be used. It only exists for Twig internal purposes.
* (for instance, the include or extends tag does not make any sense for a string
* loader).
* *
* When using this loader with a cache mechanism, you should know that a new cache * When using this loader with a cache mechanism, you should know that a new cache
* key is generated each time a template content "changes" (the cache key being the * key is generated each time a template content "changes" (the cache key being the
* source code of the template). If you don't want to see your cache grows out of * source code of the template). If you don't want to see your cache grows out of
* control, you need to take care of clearing the old cache file by yourself. * control, you need to take care of clearing the old cache file by yourself.
* *
* @deprecated since 1.18.1 (to be removed in 2.0)
*
* @internal
*
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*/ */
class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
{ {
/**
* {@inheritdoc}
*/
public function getSource($name) public function getSource($name)
{ {
@trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
return $name; return $name;
} }
/** public function getSourceContext($name)
* {@inheritdoc} {
*/ return new Twig_Source($name, $name);
}
public function exists($name) public function exists($name)
{ {
return true; return true;
} }
/**
* {@inheritdoc}
*/
public function getCacheKey($name) public function getCacheKey($name)
{ {
return $name; return $name;
} }
/**
* {@inheritdoc}
*/
public function isFresh($name, $time) public function isFresh($name, $time)
{ {
return true; return true;

13
inc/lib/Twig/LoaderInterface.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -24,6 +24,8 @@ interface Twig_LoaderInterface
* @return string The template source code * @return string The template source code
* *
* @throws Twig_Error_Loader When $name is not found * @throws Twig_Error_Loader When $name is not found
*
* @deprecated since 1.27 (to be removed in 2.0), implement Twig_SourceContextLoaderInterface
*/ */
public function getSource($name); public function getSource($name);
@ -41,12 +43,15 @@ interface Twig_LoaderInterface
/** /**
* Returns true if the template is still fresh. * Returns true if the template is still fresh.
* *
* @param string $name The template name * @param string $name The template name
* @param timestamp $time The last modification time of the cached template * @param int $time Timestamp of the last modification time of the
* cached template
* *
* @return Boolean true if the template is fresh, false otherwise * @return bool true if the template is fresh, false otherwise
* *
* @throws Twig_Error_Loader When $name is not found * @throws Twig_Error_Loader When $name is not found
*/ */
public function isFresh($name, $time); public function isFresh($name, $time);
} }
class_alias('Twig_LoaderInterface', 'Twig\Loader\LoaderInterface', false);

4
inc/lib/Twig/Markup.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -35,3 +35,5 @@ class Twig_Markup implements Countable
return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content); return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content);
} }
} }
class_alias('Twig_Markup', 'Twig\Markup', false);

124
inc/lib/Twig/Node.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -22,19 +22,26 @@ class Twig_Node implements Twig_NodeInterface
protected $lineno; protected $lineno;
protected $tag; protected $tag;
private $name;
/** /**
* Constructor. * Constructor.
* *
* The nodes are automatically made available as properties ($this->node). * The nodes are automatically made available as properties ($this->node).
* The attributes are automatically made available as array items ($this['name']). * The attributes are automatically made available as array items ($this['name']).
* *
* @param array $nodes An array of named nodes * @param array $nodes An array of named nodes
* @param array $attributes An array of attributes (should not be nodes) * @param array $attributes An array of attributes (should not be nodes)
* @param integer $lineno The line number * @param int $lineno The line number
* @param string $tag The tag name associated with the Node * @param string $tag The tag name associated with the Node
*/ */
public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null) public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null)
{ {
foreach ($nodes as $name => $node) {
if (!$node instanceof Twig_NodeInterface) {
@trigger_error(sprintf('Using "%s" for the value of node "%s" of "%s" is deprecated since version 1.25 and will be removed in 2.0.', is_object($node) ? get_class($node) : null === $node ? 'null' : gettype($node), $name, get_class($this)), E_USER_DEPRECATED);
}
}
$this->nodes = $nodes; $this->nodes = $nodes;
$this->attributes = $attributes; $this->attributes = $attributes;
$this->lineno = $lineno; $this->lineno = $lineno;
@ -69,8 +76,13 @@ class Twig_Node implements Twig_NodeInterface
return implode("\n", $repr); return implode("\n", $repr);
} }
/**
* @deprecated since 1.16.1 (to be removed in 2.0)
*/
public function toXml($asDom = false) public function toXml($asDom = false)
{ {
@trigger_error(sprintf('%s is deprecated since version 1.16.1 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED);
$dom = new DOMDocument('1.0', 'UTF-8'); $dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true; $dom->formatOutput = true;
$dom->appendChild($xml = $dom->createElement('twig')); $dom->appendChild($xml = $dom->createElement('twig'));
@ -96,7 +108,7 @@ class Twig_Node implements Twig_NodeInterface
$node->appendChild($child); $node->appendChild($child);
} }
return $asDom ? $dom : $dom->saveXml(); return $asDom ? $dom : $dom->saveXML();
} }
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
@ -106,8 +118,18 @@ class Twig_Node implements Twig_NodeInterface
} }
} }
public function getTemplateLine()
{
return $this->lineno;
}
/**
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function getLine() public function getLine()
{ {
@trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateLine() instead.', E_USER_DEPRECATED);
return $this->lineno; return $this->lineno;
} }
@ -117,11 +139,7 @@ class Twig_Node implements Twig_NodeInterface
} }
/** /**
* Returns true if the attribute is defined. * @return bool
*
* @param string The attribute name
*
* @return Boolean true if the attribute is defined, false otherwise
*/ */
public function hasAttribute($name) public function hasAttribute($name)
{ {
@ -129,11 +147,7 @@ class Twig_Node implements Twig_NodeInterface
} }
/** /**
* Gets an attribute. * @return mixed
*
* @param string The attribute name
*
* @return mixed The attribute value
*/ */
public function getAttribute($name) public function getAttribute($name)
{ {
@ -145,32 +159,21 @@ class Twig_Node implements Twig_NodeInterface
} }
/** /**
* Sets an attribute. * @param string $name
* * @param mixed $value
* @param string The attribute name
* @param mixed The attribute value
*/ */
public function setAttribute($name, $value) public function setAttribute($name, $value)
{ {
$this->attributes[$name] = $value; $this->attributes[$name] = $value;
} }
/**
* Removes an attribute.
*
* @param string The attribute name
*/
public function removeAttribute($name) public function removeAttribute($name)
{ {
unset($this->attributes[$name]); unset($this->attributes[$name]);
} }
/** /**
* Returns true if the node with the given identifier exists. * @return bool
*
* @param string The node name
*
* @return Boolean true if the node with the given name exists, false otherwise
*/ */
public function hasNode($name) public function hasNode($name)
{ {
@ -178,11 +181,7 @@ class Twig_Node implements Twig_NodeInterface
} }
/** /**
* Gets a node by name. * @return Twig_Node
*
* @param string The node name
*
* @return Twig_Node A Twig_Node instance
*/ */
public function getNode($name) public function getNode($name)
{ {
@ -193,22 +192,15 @@ class Twig_Node implements Twig_NodeInterface
return $this->nodes[$name]; return $this->nodes[$name];
} }
/**
* Sets a node.
*
* @param string The node name
* @param Twig_Node A Twig_Node instance
*/
public function setNode($name, $node = null) public function setNode($name, $node = null)
{ {
if (!$node instanceof Twig_NodeInterface) {
@trigger_error(sprintf('Using "%s" for the value of node "%s" of "%s" is deprecated since version 1.25 and will be removed in 2.0.', is_object($node) ? get_class($node) : null === $node ? 'null' : gettype($node), $name, get_class($this)), E_USER_DEPRECATED);
}
$this->nodes[$name] = $node; $this->nodes[$name] = $node;
} }
/**
* Removes a node by name.
*
* @param string The node name
*/
public function removeNode($name) public function removeNode($name)
{ {
unset($this->nodes[$name]); unset($this->nodes[$name]);
@ -223,4 +215,42 @@ class Twig_Node implements Twig_NodeInterface
{ {
return new ArrayIterator($this->nodes); return new ArrayIterator($this->nodes);
} }
public function setTemplateName($name)
{
$this->name = $name;
foreach ($this->nodes as $node) {
if (null !== $node) {
$node->setTemplateName($name);
}
}
}
public function getTemplateName()
{
return $this->name;
}
/**
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function setFilename($name)
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use setTemplateName() instead.', E_USER_DEPRECATED);
$this->setTemplateName($name);
}
/**
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function getFilename()
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateName() instead.', E_USER_DEPRECATED);
return $this->name;
}
} }
class_alias('Twig_Node', 'Twig\Node\Node', false);
class_exists('Twig_Compiler');

9
inc/lib/Twig/Node/AutoEscape.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -27,13 +27,10 @@ class Twig_Node_AutoEscape extends Twig_Node
parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag); parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag);
} }
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
$compiler->subcompile($this->getNode('body')); $compiler->subcompile($this->getNode('body'));
} }
} }
class_alias('Twig_Node_AutoEscape', 'Twig\Node\AutoEscapeNode', false);

11
inc/lib/Twig/Node/Block.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -22,11 +22,6 @@ class Twig_Node_Block extends Twig_Node
parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag); parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag);
} }
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
$compiler $compiler
@ -42,3 +37,5 @@ class Twig_Node_Block extends Twig_Node
; ;
} }
} }
class_alias('Twig_Node_Block', 'Twig\Node\BlockNode', false);

11
inc/lib/Twig/Node/BlockReference.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -22,11 +22,6 @@ class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInter
parent::__construct(array(), array('name' => $name), $lineno, $tag); parent::__construct(array(), array('name' => $name), $lineno, $tag);
} }
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
$compiler $compiler
@ -35,3 +30,5 @@ class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInter
; ;
} }
} }
class_alias('Twig_Node_BlockReference', 'Twig\Node\BlockReferenceNode', false);

4
inc/lib/Twig/Node/Body.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2011 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -17,3 +17,5 @@
class Twig_Node_Body extends Twig_Node class Twig_Node_Body extends Twig_Node
{ {
} }
class_alias('Twig_Node_Body', 'Twig\Node\BodyNode', false);

80
inc/lib/Twig/Node/CheckSecurity.php

@ -0,0 +1,80 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_CheckSecurity extends Twig_Node
{
protected $usedFilters;
protected $usedTags;
protected $usedFunctions;
public function __construct(array $usedFilters, array $usedTags, array $usedFunctions)
{
$this->usedFilters = $usedFilters;
$this->usedTags = $usedTags;
$this->usedFunctions = $usedFunctions;
parent::__construct();
}
public function compile(Twig_Compiler $compiler)
{
$tags = $filters = $functions = array();
foreach (array('tags', 'filters', 'functions') as $type) {
foreach ($this->{'used'.ucfirst($type)} as $name => $node) {
if ($node instanceof Twig_Node) {
${$type}[$name] = $node->getTemplateLine();
} else {
${$type}[$node] = null;
}
}
}
$compiler
->write('$tags = ')->repr(array_filter($tags))->raw(";\n")
->write('$filters = ')->repr(array_filter($filters))->raw(";\n")
->write('$functions = ')->repr(array_filter($functions))->raw(";\n\n")
->write("try {\n")
->indent()
->write("\$this->env->getExtension('Twig_Extension_Sandbox')->checkSecurity(\n")
->indent()
->write(!$tags ? "array(),\n" : "array('".implode("', '", array_keys($tags))."'),\n")
->write(!$filters ? "array(),\n" : "array('".implode("', '", array_keys($filters))."'),\n")
->write(!$functions ? "array()\n" : "array('".implode("', '", array_keys($functions))."')\n")
->outdent()
->write(");\n")
->outdent()
->write("} catch (Twig_Sandbox_SecurityError \$e) {\n")
->indent()
->write("\$e->setSourceContext(\$this->getSourceContext());\n\n")
->write("if (\$e instanceof Twig_Sandbox_SecurityNotAllowedTagError && isset(\$tags[\$e->getTagName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$tags[\$e->getTagName()]);\n")
->outdent()
->write("} elseif (\$e instanceof Twig_Sandbox_SecurityNotAllowedFilterError && isset(\$filters[\$e->getFilterName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$filters[\$e->getFilterName()]);\n")
->outdent()
->write("} elseif (\$e instanceof Twig_Sandbox_SecurityNotAllowedFunctionError && isset(\$functions[\$e->getFunctionName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$functions[\$e->getFunctionName()]);\n")
->outdent()
->write("}\n\n")
->write("throw \$e;\n")
->outdent()
->write("}\n\n")
;
}
}
class_alias('Twig_Node_CheckSecurity', 'Twig\Node\CheckSecurityNode', false);

9
inc/lib/Twig/Node/Do.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2011 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -21,11 +21,6 @@ class Twig_Node_Do extends Twig_Node
parent::__construct(array('expr' => $expr), array(), $lineno, $tag); 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) public function compile(Twig_Compiler $compiler)
{ {
$compiler $compiler
@ -36,3 +31,5 @@ class Twig_Node_Do extends Twig_Node
; ;
} }
} }
class_alias('Twig_Node_Do', 'Twig\Node\DoNode', false);

20
inc/lib/Twig/Node/Embed.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2012 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -17,22 +17,30 @@
class Twig_Node_Embed extends Twig_Node_Include 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) // 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) public function __construct($name, $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); parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
$this->setAttribute('filename', $filename); $this->setAttribute('name', $name);
// to be removed in 2.0, used name instead
$this->setAttribute('filename', $name);
$this->setAttribute('index', $index); $this->setAttribute('index', $index);
} }
protected function addGetTemplate(Twig_Compiler $compiler) protected function addGetTemplate(Twig_Compiler $compiler)
{ {
$compiler $compiler
->write("\$this->env->loadTemplate(") ->write('$this->loadTemplate(')
->string($this->getAttribute('filename')) ->string($this->getAttribute('name'))
->raw(', ')
->repr($this->getTemplateName())
->raw(', ')
->repr($this->getTemplateLine())
->raw(', ') ->raw(', ')
->string($this->getAttribute('index')) ->string($this->getAttribute('index'))
->raw(")") ->raw(')')
; ;
} }
} }
class_alias('Twig_Node_Embed', 'Twig\Node\EmbedNode', false);

6
inc/lib/Twig/Node/Expression.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -18,3 +18,5 @@
abstract class Twig_Node_Expression extends Twig_Node abstract class Twig_Node_Expression extends Twig_Node
{ {
} }
class_alias('Twig_Node_Expression', 'Twig\Node\Expression\AbstractExpression', false);

13
inc/lib/Twig/Node/Expression/Array.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -43,7 +43,7 @@ class Twig_Node_Expression_Array extends Twig_Node_Expression
foreach ($this->getKeyValuePairs() as $pair) { foreach ($this->getKeyValuePairs() as $pair) {
// we compare the string representation of the keys // we compare the string representation of the keys
// to avoid comparing the line numbers which are not relevant here. // to avoid comparing the line numbers which are not relevant here.
if ((string) $key == (string) $pair['key']) { if ((string) $key === (string) $pair['key']) {
return true; return true;
} }
} }
@ -54,17 +54,12 @@ class Twig_Node_Expression_Array extends Twig_Node_Expression
public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null) public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null)
{ {
if (null === $key) { if (null === $key) {
$key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine()); $key = new Twig_Node_Expression_Constant(++$this->index, $value->getTemplateLine());
} }
array_push($this->nodes, $key, $value); array_push($this->nodes, $key, $value);
} }
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
$compiler->raw('array('); $compiler->raw('array(');
@ -84,3 +79,5 @@ class Twig_Node_Expression_Array extends Twig_Node_Expression
$compiler->raw(')'); $compiler->raw(')');
} }
} }
class_alias('Twig_Node_Expression_Array', 'Twig\Node\Expression\ArrayExpression', false);

11
inc/lib/Twig/Node/Expression/AssignName.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -12,11 +12,6 @@
class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name
{ {
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
$compiler $compiler
@ -26,3 +21,5 @@ class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name
; ;
} }
} }
class_alias('Twig_Node_Expression_AssignName', 'Twig\Node\Expression\AssignNameExpression', false);

11
inc/lib/Twig/Node/Expression/Binary.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -16,11 +16,6 @@ abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression
parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno); parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno);
} }
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
$compiler $compiler
@ -38,3 +33,5 @@ abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression
abstract public function operator(Twig_Compiler $compiler); abstract public function operator(Twig_Compiler $compiler);
} }
class_alias('Twig_Node_Expression_Binary', 'Twig\Node\Expression\Binary\AbstractBinary', false);

6
inc/lib/Twig/Node/Expression/Binary/Add.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Add extends Twig_Node_Expression_Binary
return $compiler->raw('+'); return $compiler->raw('+');
} }
} }
class_alias('Twig_Node_Expression_Binary_Add', 'Twig\Node\Expression\Binary\AddBinary', false);

6
inc/lib/Twig/Node/Expression/Binary/And.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_And extends Twig_Node_Expression_Binary
return $compiler->raw('&&'); return $compiler->raw('&&');
} }
} }
class_alias('Twig_Node_Expression_Binary_And', 'Twig\Node\Expression\Binary\AndBinary', false);

6
inc/lib/Twig/Node/Expression/Binary/BitwiseAnd.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_BitwiseAnd extends Twig_Node_Expression_Binary
return $compiler->raw('&'); return $compiler->raw('&');
} }
} }
class_alias('Twig_Node_Expression_Binary_BitwiseAnd', 'Twig\Node\Expression\Binary\BitwiseAndBinary', false);

6
inc/lib/Twig/Node/Expression/Binary/BitwiseOr.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_BitwiseOr extends Twig_Node_Expression_Binary
return $compiler->raw('|'); return $compiler->raw('|');
} }
} }
class_alias('Twig_Node_Expression_Binary_BitwiseOr', 'Twig\Node\Expression\Binary\BitwiseOrBinary', false);

6
inc/lib/Twig/Node/Expression/Binary/BitwiseXor.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_BitwiseXor extends Twig_Node_Expression_Binary
return $compiler->raw('^'); return $compiler->raw('^');
} }
} }
class_alias('Twig_Node_Expression_Binary_BitwiseXor', 'Twig\Node\Expression\Binary\BitwiseXorBinary', false);

6
inc/lib/Twig/Node/Expression/Binary/Concat.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Concat extends Twig_Node_Expression_Binary
return $compiler->raw('.'); return $compiler->raw('.');
} }
} }
class_alias('Twig_Node_Expression_Binary_Concat', 'Twig\Node\Expression\Binary\ConcatBinary', false);

6
inc/lib/Twig/Node/Expression/Binary/Div.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Div extends Twig_Node_Expression_Binary
return $compiler->raw('/'); return $compiler->raw('/');
} }
} }
class_alias('Twig_Node_Expression_Binary_Div', 'Twig\Node\Expression\Binary\DivBinary', false);

32
inc/lib/Twig/Node/Expression/Binary/EndsWith.php

@ -0,0 +1,32 @@
<?php
/*
* This file is part of Twig.
*
* (c) 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_Binary_EndsWith extends Twig_Node_Expression_Binary
{
public function compile(Twig_Compiler $compiler)
{
$left = $compiler->getVarName();
$right = $compiler->getVarName();
$compiler
->raw(sprintf('(is_string($%s = ', $left))
->subcompile($this->getNode('left'))
->raw(sprintf(') && is_string($%s = ', $right))
->subcompile($this->getNode('right'))
->raw(sprintf(') && (\'\' === $%2$s || $%2$s === substr($%1$s, -strlen($%2$s))))', $left, $right))
;
}
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('');
}
}
class_alias('Twig_Node_Expression_Binary_EndsWith', 'Twig\Node\Expression\Binary\EndsWithBinary', false);

4
inc/lib/Twig/Node/Expression/Binary/Equal.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -15,3 +15,5 @@ class Twig_Node_Expression_Binary_Equal extends Twig_Node_Expression_Binary
return $compiler->raw('=='); return $compiler->raw('==');
} }
} }
class_alias('Twig_Node_Expression_Binary_Equal', 'Twig\Node\Expression\Binary\EqualBinary', false);

13
inc/lib/Twig/Node/Expression/Binary/FloorDiv.php

@ -3,23 +3,18 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary
{ {
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
$compiler->raw('intval(floor('); $compiler->raw('(int) floor(');
parent::compile($compiler); parent::compile($compiler);
$compiler->raw('))'); $compiler->raw(')');
} }
public function operator(Twig_Compiler $compiler) public function operator(Twig_Compiler $compiler)
@ -27,3 +22,5 @@ class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary
return $compiler->raw('/'); return $compiler->raw('/');
} }
} }
class_alias('Twig_Node_Expression_Binary_FloorDiv', 'Twig\Node\Expression\Binary\FloorDivBinary', false);

4
inc/lib/Twig/Node/Expression/Binary/Greater.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -15,3 +15,5 @@ class Twig_Node_Expression_Binary_Greater extends Twig_Node_Expression_Binary
return $compiler->raw('>'); return $compiler->raw('>');
} }
} }
class_alias('Twig_Node_Expression_Binary_Greater', 'Twig\Node\Expression\Binary\GreaterBinary', false);

4
inc/lib/Twig/Node/Expression/Binary/GreaterEqual.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -15,3 +15,5 @@ class Twig_Node_Expression_Binary_GreaterEqual extends Twig_Node_Expression_Bina
return $compiler->raw('>='); return $compiler->raw('>=');
} }
} }
class_alias('Twig_Node_Expression_Binary_GreaterEqual', 'Twig\Node\Expression\Binary\GreaterEqualBinary', false);

9
inc/lib/Twig/Node/Expression/Binary/In.php

@ -3,18 +3,13 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
class Twig_Node_Expression_Binary_In extends Twig_Node_Expression_Binary class Twig_Node_Expression_Binary_In extends Twig_Node_Expression_Binary
{ {
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
$compiler $compiler
@ -31,3 +26,5 @@ class Twig_Node_Expression_Binary_In extends Twig_Node_Expression_Binary
return $compiler->raw('in'); return $compiler->raw('in');
} }
} }
class_alias('Twig_Node_Expression_Binary_In', 'Twig\Node\Expression\Binary\InBinary', false);

4
inc/lib/Twig/Node/Expression/Binary/Less.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -15,3 +15,5 @@ class Twig_Node_Expression_Binary_Less extends Twig_Node_Expression_Binary
return $compiler->raw('<'); return $compiler->raw('<');
} }
} }
class_alias('Twig_Node_Expression_Binary_Less', 'Twig\Node\Expression\Binary\LessBinary', false);

4
inc/lib/Twig/Node/Expression/Binary/LessEqual.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -15,3 +15,5 @@ class Twig_Node_Expression_Binary_LessEqual extends Twig_Node_Expression_Binary
return $compiler->raw('<='); return $compiler->raw('<=');
} }
} }
class_alias('Twig_Node_Expression_Binary_LessEqual', 'Twig\Node\Expression\Binary\LessEqualBinary', false);

30
inc/lib/Twig/Node/Expression/Binary/Matches.php

@ -0,0 +1,30 @@
<?php
/*
* This file is part of Twig.
*
* (c) 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_Binary_Matches extends Twig_Node_Expression_Binary
{
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('preg_match(')
->subcompile($this->getNode('right'))
->raw(', ')
->subcompile($this->getNode('left'))
->raw(')')
;
}
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('');
}
}
class_alias('Twig_Node_Expression_Binary_Matches', 'Twig\Node\Expression\Binary\MatchesBinary', false);

6
inc/lib/Twig/Node/Expression/Binary/Mod.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Mod extends Twig_Node_Expression_Binary
return $compiler->raw('%'); return $compiler->raw('%');
} }
} }
class_alias('Twig_Node_Expression_Binary_Mod', 'Twig\Node\Expression\Binary\ModBinary', false);

6
inc/lib/Twig/Node/Expression/Binary/Mul.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Mul extends Twig_Node_Expression_Binary
return $compiler->raw('*'); return $compiler->raw('*');
} }
} }
class_alias('Twig_Node_Expression_Binary_Mul', 'Twig\Node\Expression\Binary\MulBinary', false);

4
inc/lib/Twig/Node/Expression/Binary/NotEqual.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -15,3 +15,5 @@ class Twig_Node_Expression_Binary_NotEqual extends Twig_Node_Expression_Binary
return $compiler->raw('!='); return $compiler->raw('!=');
} }
} }
class_alias('Twig_Node_Expression_Binary_NotEqual', 'Twig\Node\Expression\Binary\NotEqualBinary', false);

9
inc/lib/Twig/Node/Expression/Binary/NotIn.php

@ -3,18 +3,13 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
class Twig_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary class Twig_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary
{ {
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
$compiler $compiler
@ -31,3 +26,5 @@ class Twig_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary
return $compiler->raw('not in'); return $compiler->raw('not in');
} }
} }
class_alias('Twig_Node_Expression_Binary_NotIn', 'Twig\Node\Expression\Binary\NotInBinary', false);

6
inc/lib/Twig/Node/Expression/Binary/Or.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Or extends Twig_Node_Expression_Binary
return $compiler->raw('||'); return $compiler->raw('||');
} }
} }
class_alias('Twig_Node_Expression_Binary_Or', 'Twig\Node\Expression\Binary\OrBinary', false);

13
inc/lib/Twig/Node/Expression/Binary/Power.php

@ -3,20 +3,19 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
class Twig_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary class Twig_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary
{ {
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
if (PHP_VERSION_ID >= 50600) {
return parent::compile($compiler);
}
$compiler $compiler
->raw('pow(') ->raw('pow(')
->subcompile($this->getNode('left')) ->subcompile($this->getNode('left'))
@ -31,3 +30,5 @@ class Twig_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary
return $compiler->raw('**'); return $compiler->raw('**');
} }
} }
class_alias('Twig_Node_Expression_Binary_Power', 'Twig\Node\Expression\Binary\PowerBinary', false);

9
inc/lib/Twig/Node/Expression/Binary/Range.php

@ -3,18 +3,13 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
class Twig_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary class Twig_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary
{ {
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
$compiler $compiler
@ -31,3 +26,5 @@ class Twig_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary
return $compiler->raw('..'); return $compiler->raw('..');
} }
} }
class_alias('Twig_Node_Expression_Binary_Range', 'Twig\Node\Expression\Binary\RangeBinary', false);

32
inc/lib/Twig/Node/Expression/Binary/StartsWith.php

@ -0,0 +1,32 @@
<?php
/*
* This file is part of Twig.
*
* (c) 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_Binary_StartsWith extends Twig_Node_Expression_Binary
{
public function compile(Twig_Compiler $compiler)
{
$left = $compiler->getVarName();
$right = $compiler->getVarName();
$compiler
->raw(sprintf('(is_string($%s = ', $left))
->subcompile($this->getNode('left'))
->raw(sprintf(') && is_string($%s = ', $right))
->subcompile($this->getNode('right'))
->raw(sprintf(') && (\'\' === $%2$s || 0 === strpos($%1$s, $%2$s)))', $left, $right))
;
}
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('');
}
}
class_alias('Twig_Node_Expression_Binary_StartsWith', 'Twig\Node\Expression\Binary\StartsWithBinary', false);

6
inc/lib/Twig/Node/Expression/Binary/Sub.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Sub extends Twig_Node_Expression_Binary
return $compiler->raw('-'); return $compiler->raw('-');
} }
} }
class_alias('Twig_Node_Expression_Binary_Sub', 'Twig\Node\Expression\Binary\SubBinary', false);

84
inc/lib/Twig/Node/Expression/BlockReference.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -17,35 +17,77 @@
*/ */
class Twig_Node_Expression_BlockReference extends Twig_Node_Expression class Twig_Node_Expression_BlockReference extends Twig_Node_Expression
{ {
public function __construct(Twig_NodeInterface $name, $asString = false, $lineno, $tag = null) /**
* @param Twig_Node|null $template
*/
public function __construct(Twig_NodeInterface $name, $template = null, $lineno, $tag = null)
{ {
parent::__construct(array('name' => $name), array('as_string' => $asString, 'output' => false), $lineno, $tag); if (is_bool($template)) {
@trigger_error(sprintf('The %s method "$asString" argument is deprecated since version 1.28 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED);
$template = null;
}
$nodes = array('name' => $name);
if (null !== $template) {
$nodes['template'] = $template;
}
parent::__construct($nodes, array('is_defined_test' => false, 'output' => false), $lineno, $tag);
} }
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
if ($this->getAttribute('as_string')) { if ($this->getAttribute('is_defined_test')) {
$compiler->raw('(string) '); $this->compileTemplateCall($compiler, 'hasBlock');
} else {
if ($this->getAttribute('output')) {
$compiler->addDebugInfo($this);
$this
->compileTemplateCall($compiler, 'displayBlock')
->raw(";\n");
} else {
$this->compileTemplateCall($compiler, 'renderBlock');
}
} }
}
if ($this->getAttribute('output')) { private function compileTemplateCall(Twig_Compiler $compiler, $method)
$compiler {
->addDebugInfo($this) if (!$this->hasNode('template')) {
->write("\$this->displayBlock(") $compiler->write('$this');
->subcompile($this->getNode('name'))
->raw(", \$context, \$blocks);\n")
;
} else { } else {
$compiler $compiler
->raw("\$this->renderBlock(") ->write('$this->loadTemplate(')
->subcompile($this->getNode('name')) ->subcompile($this->getNode('template'))
->raw(", \$context, \$blocks)") ->raw(', ')
->repr($this->getTemplateName())
->raw(', ')
->repr($this->getTemplateLine())
->raw(')')
; ;
} }
$compiler->raw(sprintf('->%s', $method));
$this->compileBlockArguments($compiler);
return $compiler;
}
private function compileBlockArguments(Twig_Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('name'))
->raw(', $context');
if (!$this->hasNode('template')) {
$compiler->raw(', $blocks');
}
return $compiler->raw(')');
} }
} }
class_alias('Twig_Node_Expression_BlockReference', 'Twig\Node\Expression\BlockReferenceExpression', false);

209
inc/lib/Twig/Node/Expression/Call.php

@ -3,27 +3,36 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2012 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
abstract class Twig_Node_Expression_Call extends Twig_Node_Expression abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
{ {
private $reflector;
protected function compileCallable(Twig_Compiler $compiler) protected function compileCallable(Twig_Compiler $compiler)
{ {
$callable = $this->getAttribute('callable');
$closingParenthesis = false; $closingParenthesis = false;
if ($callable) { if ($this->hasAttribute('callable') && $callable = $this->getAttribute('callable')) {
if (is_string($callable)) { if (is_string($callable) && false === strpos($callable, '::')) {
$compiler->raw($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 { } else {
$type = ucfirst($this->getAttribute('type')); list($r, $callable) = $this->reflectCallable($callable);
$compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name'))); if ($r instanceof ReflectionMethod && is_string($callable[0])) {
$closingParenthesis = true; if ($r->isStatic()) {
$compiler->raw(sprintf('%s::%s', $callable[0], $callable[1]));
} else {
$compiler->raw(sprintf('$this->env->getRuntime(\'%s\')->%s', $callable[0], $callable[1]));
}
} elseif ($r instanceof ReflectionMethod && $callable[0] instanceof Twig_ExtensionInterface) {
$compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', get_class($callable[0]), $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 { } else {
$compiler->raw($this->getAttribute('thing')->compile()); $compiler->raw($this->getAttribute('thing')->compile());
@ -73,7 +82,7 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
$first = false; $first = false;
} }
if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) { if ($this->hasNode('arguments')) {
$callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null; $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null;
$arguments = $this->getArguments($callable, $this->getNode('arguments')); $arguments = $this->getArguments($callable, $this->getNode('arguments'));
@ -92,6 +101,9 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
protected function getArguments($callable, $arguments) protected function getArguments($callable, $arguments)
{ {
$callType = $this->getAttribute('type');
$callName = $this->getAttribute('name');
$parameters = array(); $parameters = array();
$named = false; $named = false;
foreach ($arguments as $name => $node) { foreach ($arguments as $name => $node) {
@ -99,73 +111,101 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
$named = true; $named = true;
$name = $this->normalizeName($name); $name = $this->normalizeName($name);
} elseif ($named) { } 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'))); throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $callType, $callName));
} }
$parameters[$name] = $node; $parameters[$name] = $node;
} }
if (!$named) { $isVariadic = $this->hasAttribute('is_variadic') && $this->getAttribute('is_variadic');
if (!$named && !$isVariadic) {
return $parameters; return $parameters;
} }
if (!$callable) { if (!$callable) {
throw new LogicException(sprintf('Named arguments are not supported for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name'))); if ($named) {
} $message = sprintf('Named arguments are not supported for %s "%s".', $callType, $callName);
} else {
// manage named arguments $message = sprintf('Arbitrary positional arguments are not supported for %s "%s".', $callType, $callName);
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);
} }
throw new LogicException($message);
} }
$callableParameters = $this->getCallableParameters($callable, $isVariadic);
$arguments = array(); $arguments = array();
$names = array();
$missingArguments = array();
$optionalArguments = array();
$pos = 0; $pos = 0;
foreach ($definition as $param) { foreach ($callableParameters as $callableParameter) {
$name = $this->normalizeName($param->name); $names[] = $name = $this->normalizeName($callableParameter->name);
if (array_key_exists($name, $parameters)) { if (array_key_exists($name, $parameters)) {
if (array_key_exists($pos, $parameters)) { if (array_key_exists($pos, $parameters)) {
throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name'))); throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $callType, $callName));
}
if (count($missingArguments)) {
throw new Twig_Error_Syntax(sprintf(
'Argument "%s" could not be assigned for %s "%s(%s)" because it is mapped to an internal PHP function which cannot determine default value for optional argument%s "%s".',
$name, $callType, $callName, implode(', ', $names), count($missingArguments) > 1 ? 's' : '', implode('", "', $missingArguments))
);
} }
$arguments = array_merge($arguments, $optionalArguments);
$arguments[] = $parameters[$name]; $arguments[] = $parameters[$name];
unset($parameters[$name]); unset($parameters[$name]);
$optionalArguments = array();
} elseif (array_key_exists($pos, $parameters)) { } elseif (array_key_exists($pos, $parameters)) {
$arguments = array_merge($arguments, $optionalArguments);
$arguments[] = $parameters[$pos]; $arguments[] = $parameters[$pos];
unset($parameters[$pos]); unset($parameters[$pos]);
$optionalArguments = array();
++$pos; ++$pos;
} elseif ($param->isDefaultValueAvailable()) { } elseif ($callableParameter->isDefaultValueAvailable()) {
$arguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1); $optionalArguments[] = new Twig_Node_Expression_Constant($callableParameter->getDefaultValue(), -1);
} elseif ($param->isOptional()) { } elseif ($callableParameter->isOptional()) {
break; if (empty($parameters)) {
break;
} else {
$missingArguments[] = $name;
}
} else { } else {
throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name'))); throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $callType, $callName));
}
}
if ($isVariadic) {
$arbitraryArguments = new Twig_Node_Expression_Array(array(), -1);
foreach ($parameters as $key => $value) {
if (is_int($key)) {
$arbitraryArguments->addElement($value);
} else {
$arbitraryArguments->addElement($value, new Twig_Node_Expression_Constant($key, -1));
}
unset($parameters[$key]);
}
if ($arbitraryArguments->count()) {
$arguments = array_merge($arguments, $optionalArguments);
$arguments[] = $arbitraryArguments;
} }
} }
if (!empty($parameters)) { if (!empty($parameters)) {
throw new Twig_Error_Syntax(sprintf('Unknown argument%s "%s" for %s "%s".', count($parameters) > 1 ? 's' : '' , implode('", "', array_keys($parameters)), $this->getAttribute('type'), $this->getAttribute('name'))); $unknownParameter = null;
foreach ($parameters as $parameter) {
if ($parameter instanceof Twig_Node) {
$unknownParameter = $parameter;
break;
}
}
throw new Twig_Error_Syntax(sprintf(
'Unknown argument%s "%s" for %s "%s(%s)".',
count($parameters) > 1 ? 's' : '', implode('", "', array_keys($parameters)), $callType, $callName, implode(', ', $names)
), $unknownParameter ? $unknownParameter->getTemplateLine() : -1);
} }
return $arguments; return $arguments;
@ -175,4 +215,77 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
{ {
return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name)); return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name));
} }
private function getCallableParameters($callable, $isVariadic)
{
list($r) = $this->reflectCallable($callable);
if (null === $r) {
return array();
}
$parameters = $r->getParameters();
if ($this->hasNode('node')) {
array_shift($parameters);
}
if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
array_shift($parameters);
}
if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
array_shift($parameters);
}
if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
foreach ($this->getAttribute('arguments') as $argument) {
array_shift($parameters);
}
}
if ($isVariadic) {
$argument = end($parameters);
if ($argument && $argument->isArray() && $argument->isDefaultValueAvailable() && array() === $argument->getDefaultValue()) {
array_pop($parameters);
} else {
$callableName = $r->name;
if ($r instanceof ReflectionMethod) {
$callableName = $r->getDeclaringClass()->name.'::'.$callableName;
}
throw new LogicException(sprintf('The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = array()".', $callableName, $this->getAttribute('type'), $this->getAttribute('name')));
}
}
return $parameters;
}
private function reflectCallable($callable)
{
if (null !== $this->reflector) {
return $this->reflector;
}
if (is_array($callable)) {
if (!method_exists($callable[0], $callable[1])) {
// __call()
return array(null, array());
}
$r = new ReflectionMethod($callable[0], $callable[1]);
} elseif (is_object($callable) && !$callable instanceof Closure) {
$r = new ReflectionObject($callable);
$r = $r->getMethod('__invoke');
$callable = array($callable, '__invoke');
} elseif (is_string($callable) && false !== $pos = strpos($callable, '::')) {
$class = substr($callable, 0, $pos);
$method = substr($callable, $pos + 2);
if (!method_exists($class, $method)) {
// __staticCall()
return array(null, array());
}
$r = new ReflectionMethod($callable);
$callable = array($class, $method);
} else {
$r = new ReflectionFunction($callable);
}
return $this->reflector = array($r, $callable);
}
} }
class_alias('Twig_Node_Expression_Call', 'Twig\Node\Expression\CallExpression', false);

6
inc/lib/Twig/Node/Expression/Conditional.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -29,3 +29,5 @@ class Twig_Node_Expression_Conditional extends Twig_Node_Expression
; ;
} }
} }
class_alias('Twig_Node_Expression_Conditional', 'Twig\Node\Expression\ConditionalExpression', false);

6
inc/lib/Twig/Node/Expression/Constant.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -21,3 +21,5 @@ class Twig_Node_Expression_Constant extends Twig_Node_Expression
$compiler->repr($this->getAttribute('value')); $compiler->repr($this->getAttribute('value'));
} }
} }
class_alias('Twig_Node_Expression_Constant', 'Twig\Node\Expression\ConstantExpression', false);

11
inc/lib/Twig/Node/Expression/ExtensionReference.php

@ -3,16 +3,20 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
@trigger_error('The Twig_Node_Expression_ExtensionReference class is deprecated since version 1.23 and will be removed in 2.0.', E_USER_DEPRECATED);
/** /**
* Represents an extension call node. * Represents an extension call node.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.23 and will be removed in 2.0.
*/ */
class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression
{ {
@ -21,11 +25,6 @@ class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression
parent::__construct(array(), array('name' => $name), $lineno, $tag); parent::__construct(array(), array('name' => $name), $lineno, $tag);
} }
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
$compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name'))); $compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name')));

9
inc/lib/Twig/Node/Expression/Filter.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -30,7 +30,12 @@ class Twig_Node_Expression_Filter extends Twig_Node_Expression_Call
if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) { if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) {
$this->setAttribute('callable', $filter->getCallable()); $this->setAttribute('callable', $filter->getCallable());
} }
if ($filter instanceof Twig_SimpleFilter) {
$this->setAttribute('is_variadic', $filter->isVariadic());
}
$this->compileCallable($compiler); $this->compileCallable($compiler);
} }
} }
class_alias('Twig_Node_Expression_Filter', 'Twig\Node\Expression\FilterExpression', false);

12
inc/lib/Twig/Node/Expression/Filter/Default.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2011 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -22,13 +22,13 @@ 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) 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()); $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getTemplateLine()), $arguments, $node->getTemplateLine());
if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) { 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()); $test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getTemplateLine());
$false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine()); $false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getTemplateLine());
$node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine()); $node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getTemplateLine());
} else { } else {
$node = $default; $node = $default;
} }
@ -41,3 +41,5 @@ class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter
$compiler->subcompile($this->getNode('node')); $compiler->subcompile($this->getNode('node'));
} }
} }
class_alias('Twig_Node_Expression_Filter_Default', 'Twig\Node\Expression\Filter\DefaultFilter', false);

16
inc/lib/Twig/Node/Expression/Function.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2010 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -12,7 +12,7 @@ class Twig_Node_Expression_Function extends Twig_Node_Expression_Call
{ {
public function __construct($name, Twig_NodeInterface $arguments, $lineno) public function __construct($name, Twig_NodeInterface $arguments, $lineno)
{ {
parent::__construct(array('arguments' => $arguments), array('name' => $name), $lineno); parent::__construct(array('arguments' => $arguments), array('name' => $name, 'is_defined_test' => false), $lineno);
} }
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
@ -27,9 +27,19 @@ class Twig_Node_Expression_Function extends Twig_Node_Expression_Call
$this->setAttribute('needs_context', $function->needsContext()); $this->setAttribute('needs_context', $function->needsContext());
$this->setAttribute('arguments', $function->getArguments()); $this->setAttribute('arguments', $function->getArguments());
if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) { if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) {
$this->setAttribute('callable', $function->getCallable()); $callable = $function->getCallable();
if ('constant' === $name && $this->getAttribute('is_defined_test')) {
$callable = 'twig_constant_is_defined';
}
$this->setAttribute('callable', $callable);
}
if ($function instanceof Twig_SimpleFunction) {
$this->setAttribute('is_variadic', $function->isVariadic());
} }
$this->compileCallable($compiler); $this->compileCallable($compiler);
} }
} }
class_alias('Twig_Node_Expression_Function', 'Twig\Node\Expression\FunctionExpression', false);

49
inc/lib/Twig/Node/Expression/GetAttr.php

@ -3,21 +3,30 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
class Twig_Node_Expression_GetAttr extends Twig_Node_Expression class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
{ {
public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression_Array $arguments, $type, $lineno) public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression $arguments = null, $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); $nodes = array('node' => $node, 'attribute' => $attribute);
if (null !== $arguments) {
$nodes['arguments'] = $arguments;
}
parent::__construct($nodes, array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno);
} }
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
if ($this->getAttribute('disable_c_ext')) {
@trigger_error(sprintf('Using the "disable_c_ext" attribute on %s is deprecated since version 1.30 and will be removed in 2.0.', __CLASS__), E_USER_DEPRECATED);
}
if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) { if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) {
$compiler->raw('twig_template_get_attributes($this, '); $compiler->raw('twig_template_get_attributes($this, ');
} else { } else {
@ -32,22 +41,34 @@ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
$compiler->raw(', ')->subcompile($this->getNode('attribute')); $compiler->raw(', ')->subcompile($this->getNode('attribute'));
if (count($this->getNode('arguments')) || Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { // only generate optional arguments when needed (to make generated code more readable)
$compiler->raw(', ')->subcompile($this->getNode('arguments')); $needFourth = $this->getAttribute('ignore_strict_check');
$needThird = $needFourth || $this->getAttribute('is_defined_test');
$needSecond = $needThird || Twig_Template::ANY_CALL !== $this->getAttribute('type');
$needFirst = $needSecond || $this->hasNode('arguments');
if (Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { if ($needFirst) {
$compiler->raw(', ')->repr($this->getAttribute('type')); if ($this->hasNode('arguments')) {
$compiler->raw(', ')->subcompile($this->getNode('arguments'));
} else {
$compiler->raw(', array()');
} }
}
if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { if ($needSecond) {
$compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false')); $compiler->raw(', ')->repr($this->getAttribute('type'));
} }
if ($this->getAttribute('ignore_strict_check')) { if ($needThird) {
$compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false')); $compiler->raw(', ')->repr($this->getAttribute('is_defined_test'));
} }
if ($needFourth) {
$compiler->raw(', ')->repr($this->getAttribute('ignore_strict_check'));
} }
$compiler->raw(')'); $compiler->raw(')');
} }
} }
class_alias('Twig_Node_Expression_GetAttr', 'Twig\Node\Expression\GetAttrExpression', false);

4
inc/lib/Twig/Node/Expression/MethodCall.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2012 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -39,3 +39,5 @@ class Twig_Node_Expression_MethodCall extends Twig_Node_Expression
$compiler->raw(')'); $compiler->raw(')');
} }
} }
class_alias('Twig_Node_Expression_MethodCall', 'Twig\Node\Expression\MethodCallExpression', false);

28
inc/lib/Twig/Node/Expression/Name.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -12,7 +12,7 @@
class Twig_Node_Expression_Name extends Twig_Node_Expression class Twig_Node_Expression_Name extends Twig_Node_Expression
{ {
protected $specialVars = array( protected $specialVars = array(
'_self' => '$this', '_self' => '$this',
'_context' => '$context', '_context' => '$context',
'_charset' => '$this->env->getCharset()', '_charset' => '$this->env->getCharset()',
); );
@ -26,6 +26,8 @@ class Twig_Node_Expression_Name extends Twig_Node_Expression
{ {
$name = $this->getAttribute('name'); $name = $this->getAttribute('name');
$compiler->addDebugInfo($this);
if ($this->getAttribute('is_defined_test')) { if ($this->getAttribute('is_defined_test')) {
if ($this->isSpecial()) { if ($this->isSpecial()) {
$compiler->repr(true); $compiler->repr(true);
@ -41,10 +43,20 @@ class Twig_Node_Expression_Name extends Twig_Node_Expression
->raw(']') ->raw(']')
; ;
} else { } else {
// remove the non-PHP 5.4 version when PHP 5.3 support is dropped if (PHP_VERSION_ID >= 70000) {
// as the non-optimized version is just a workaround for slow ternary operator // use PHP 7 null coalescing operator
// when the context has a lot of variables $compiler
if (version_compare(phpversion(), '5.4.0RC1', '>=')) { ->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('))');
}
} elseif (PHP_VERSION_ID >= 50400) {
// PHP 5.4 ternary operator performance was optimized // PHP 5.4 ternary operator performance was optimized
$compiler $compiler
->raw('(isset($context[') ->raw('(isset($context[')
@ -86,3 +98,5 @@ class Twig_Node_Expression_Name extends Twig_Node_Expression
return !$this->isSpecial() && !$this->getAttribute('is_defined_test'); return !$this->isSpecial() && !$this->getAttribute('is_defined_test');
} }
} }
class_alias('Twig_Node_Expression_Name', 'Twig\Node\Expression\NameExpression', false);

48
inc/lib/Twig/Node/Expression/NullCoalesce.php

@ -0,0 +1,48 @@
<?php
/*
* This file is part of Twig.
*
* (c) 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_NullCoalesce extends Twig_Node_Expression_Conditional
{
public function __construct(Twig_NodeInterface $left, Twig_NodeInterface $right, $lineno)
{
$test = new Twig_Node_Expression_Binary_And(
new Twig_Node_Expression_Test_Defined(clone $left, 'defined', new Twig_Node(), $left->getTemplateLine()),
new Twig_Node_Expression_Unary_Not(new Twig_Node_Expression_Test_Null($left, 'null', new Twig_Node(), $left->getTemplateLine()), $left->getTemplateLine()),
$left->getTemplateLine()
);
parent::__construct($test, $left, $right, $lineno);
}
public function compile(Twig_Compiler $compiler)
{
/*
* This optimizes only one case. PHP 7 also supports more complex expressions
* that can return null. So, for instance, if log is defined, log("foo") ?? "..." works,
* but log($a["foo"]) ?? "..." does not if $a["foo"] is not defined. More advanced
* cases might be implemented as an optimizer node visitor, but has not been done
* as benefits are probably not worth the added complexity.
*/
if (PHP_VERSION_ID >= 70000 && $this->getNode('expr2') instanceof Twig_Node_Expression_Name) {
$this->getNode('expr2')->setAttribute('always_defined', true);
$compiler
->raw('((')
->subcompile($this->getNode('expr2'))
->raw(') ?? (')
->subcompile($this->getNode('expr3'))
->raw('))')
;
} else {
parent::compile($compiler);
}
}
}
class_alias('Twig_Node_Expression_NullCoalesce', 'Twig\Node\Expression\NullCoalesceExpression', false);

17
inc/lib/Twig/Node/Expression/Parent.php

@ -3,8 +3,8 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2009 Fabien Potencier * (c) Fabien Potencier
* (c) 2009 Armin Ronacher * (c) Armin Ronacher
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -22,26 +22,23 @@ class Twig_Node_Expression_Parent extends Twig_Node_Expression
parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag); parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag);
} }
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler) public function compile(Twig_Compiler $compiler)
{ {
if ($this->getAttribute('output')) { if ($this->getAttribute('output')) {
$compiler $compiler
->addDebugInfo($this) ->addDebugInfo($this)
->write("\$this->displayParentBlock(") ->write('$this->displayParentBlock(')
->string($this->getAttribute('name')) ->string($this->getAttribute('name'))
->raw(", \$context, \$blocks);\n") ->raw(", \$context, \$blocks);\n")
; ;
} else { } else {
$compiler $compiler
->raw("\$this->renderParentBlock(") ->raw('$this->renderParentBlock(')
->string($this->getAttribute('name')) ->string($this->getAttribute('name'))
->raw(", \$context, \$blocks)") ->raw(', $context, $blocks)')
; ;
} }
} }
} }
class_alias('Twig_Node_Expression_Parent', 'Twig\Node\Expression\ParentExpression', false);

4
inc/lib/Twig/Node/Expression/TempName.php

@ -3,7 +3,7 @@
/* /*
* This file is part of Twig. * This file is part of Twig.
* *
* (c) 2011 Fabien Potencier * (c) Fabien Potencier
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@ -24,3 +24,5 @@ class Twig_Node_Expression_TempName extends Twig_Node_Expression
; ;
} }
} }
class_alias('Twig_Node_Expression_TempName', 'Twig\Node\Expression\TempNameExpression', false);

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save