parent
07fd93b3d2
commit
b6099390e8
@ -0,0 +1,46 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Autoloads Twig classes. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Autoloader |
||||
{ |
||||
/** |
||||
* Registers Twig_Autoloader as an SPL autoloader. |
||||
*/ |
||||
static public function register() |
||||
{ |
||||
ini_set('unserialize_callback_func', 'spl_autoload_call'); |
||||
spl_autoload_register(array(new self, 'autoload')); |
||||
} |
||||
|
||||
/** |
||||
* Handles autoloading of classes. |
||||
* |
||||
* @param string $class A class name. |
||||
* |
||||
* @return boolean Returns true if the class has been loaded |
||||
*/ |
||||
static public function autoload($class) |
||||
{ |
||||
if (0 !== strpos($class, 'Twig')) { |
||||
return; |
||||
} |
||||
|
||||
if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) { |
||||
require $file; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,242 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Compiles a node to PHP code. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Compiler implements Twig_CompilerInterface |
||||
{ |
||||
protected $lastLine; |
||||
protected $source; |
||||
protected $indentation; |
||||
protected $env; |
||||
protected $debugInfo; |
||||
protected $sourceOffset; |
||||
protected $sourceLine; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* |
||||
* @param Twig_Environment $env The twig environment instance |
||||
*/ |
||||
public function __construct(Twig_Environment $env) |
||||
{ |
||||
$this->env = $env; |
||||
$this->debugInfo = array(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the environment instance related to this compiler. |
||||
* |
||||
* @return Twig_Environment The environment instance |
||||
*/ |
||||
public function getEnvironment() |
||||
{ |
||||
return $this->env; |
||||
} |
||||
|
||||
/** |
||||
* Gets the current PHP code after compilation. |
||||
* |
||||
* @return string The PHP code |
||||
*/ |
||||
public function getSource() |
||||
{ |
||||
return $this->source; |
||||
} |
||||
|
||||
/** |
||||
* Compiles a node. |
||||
* |
||||
* @param Twig_NodeInterface $node The node to compile |
||||
* @param integer $indentation The current indentation |
||||
* |
||||
* @return Twig_Compiler The current compiler instance |
||||
*/ |
||||
public function compile(Twig_NodeInterface $node, $indentation = 0) |
||||
{ |
||||
$this->lastLine = null; |
||||
$this->source = ''; |
||||
$this->sourceOffset = 0; |
||||
$this->sourceLine = 0; |
||||
$this->indentation = $indentation; |
||||
|
||||
$node->compile($this); |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function subcompile(Twig_NodeInterface $node, $raw = true) |
||||
{ |
||||
if (false === $raw) { |
||||
$this->addIndentation(); |
||||
} |
||||
|
||||
$node->compile($this); |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* Adds a raw string to the compiled code. |
||||
* |
||||
* @param string $string The string |
||||
* |
||||
* @return Twig_Compiler The current compiler instance |
||||
*/ |
||||
public function raw($string) |
||||
{ |
||||
$this->source .= $string; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* Writes a string to the compiled code by adding indentation. |
||||
* |
||||
* @return Twig_Compiler The current compiler instance |
||||
*/ |
||||
public function write() |
||||
{ |
||||
$strings = func_get_args(); |
||||
foreach ($strings as $string) { |
||||
$this->addIndentation(); |
||||
$this->source .= $string; |
||||
} |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function addIndentation() |
||||
{ |
||||
$this->source .= str_repeat(' ', $this->indentation * 4); |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* Adds a quoted string to the compiled code. |
||||
* |
||||
* @param string $value The string |
||||
* |
||||
* @return Twig_Compiler The current compiler instance |
||||
*/ |
||||
public function string($value) |
||||
{ |
||||
$this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\")); |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* Returns a PHP representation of a given value. |
||||
* |
||||
* @param mixed $value The value to convert |
||||
* |
||||
* @return Twig_Compiler The current compiler instance |
||||
*/ |
||||
public function repr($value) |
||||
{ |
||||
if (is_int($value) || is_float($value)) { |
||||
if (false !== $locale = setlocale(LC_NUMERIC, 0)) { |
||||
setlocale(LC_NUMERIC, 'C'); |
||||
} |
||||
|
||||
$this->raw($value); |
||||
|
||||
if (false !== $locale) { |
||||
setlocale(LC_NUMERIC, $locale); |
||||
} |
||||
} elseif (null === $value) { |
||||
$this->raw('null'); |
||||
} elseif (is_bool($value)) { |
||||
$this->raw($value ? 'true' : 'false'); |
||||
} elseif (is_array($value)) { |
||||
$this->raw('array('); |
||||
$i = 0; |
||||
foreach ($value as $key => $value) { |
||||
if ($i++) { |
||||
$this->raw(', '); |
||||
} |
||||
$this->repr($key); |
||||
$this->raw(' => '); |
||||
$this->repr($value); |
||||
} |
||||
$this->raw(')'); |
||||
} else { |
||||
$this->string($value); |
||||
} |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* Adds debugging information. |
||||
* |
||||
* @param Twig_NodeInterface $node The related twig node |
||||
* |
||||
* @return Twig_Compiler The current compiler instance |
||||
*/ |
||||
public function addDebugInfo(Twig_NodeInterface $node) |
||||
{ |
||||
if ($node->getLine() != $this->lastLine) { |
||||
$this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset); |
||||
$this->sourceOffset = strlen($this->source); |
||||
$this->debugInfo[$this->sourceLine] = $node->getLine(); |
||||
|
||||
$this->lastLine = $node->getLine(); |
||||
$this->write("// line {$node->getLine()}\n"); |
||||
} |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function getDebugInfo() |
||||
{ |
||||
return $this->debugInfo; |
||||
} |
||||
|
||||
/** |
||||
* Indents the generated code. |
||||
* |
||||
* @param integer $step The number of indentation to add |
||||
* |
||||
* @return Twig_Compiler The current compiler instance |
||||
*/ |
||||
public function indent($step = 1) |
||||
{ |
||||
$this->indentation += $step; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* Outdents the generated code. |
||||
* |
||||
* @param integer $step The number of indentation to remove |
||||
* |
||||
* @return Twig_Compiler The current compiler instance |
||||
*/ |
||||
public function outdent($step = 1) |
||||
{ |
||||
$this->indentation -= $step; |
||||
|
||||
if ($this->indentation < 0) { |
||||
throw new Twig_Error('Unable to call outdent() as the indentation would become negative'); |
||||
} |
||||
|
||||
return $this; |
||||
} |
||||
} |
@ -0,0 +1,35 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Interface implemented by compiler classes. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
interface Twig_CompilerInterface |
||||
{ |
||||
/** |
||||
* Compiles a node. |
||||
* |
||||
* @param Twig_NodeInterface $node The node to compile |
||||
* |
||||
* @return Twig_CompilerInterface The current compiler instance |
||||
*/ |
||||
function compile(Twig_NodeInterface $node); |
||||
|
||||
/** |
||||
* Gets the current PHP code after compilation. |
||||
* |
||||
* @return string The PHP code |
||||
*/ |
||||
function getSource(); |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,176 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Twig base exception. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Error extends Exception |
||||
{ |
||||
protected $lineno; |
||||
protected $filename; |
||||
protected $rawMessage; |
||||
protected $previous; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* |
||||
* @param string $message The error message |
||||
* @param integer $lineno The template line where the error occurred |
||||
* @param string $filename The template file name where the error occurred |
||||
* @param Exception $previous The previous exception |
||||
*/ |
||||
public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null) |
||||
{ |
||||
if (-1 === $lineno || null === $filename) { |
||||
if ($trace = $this->getTemplateTrace()) { |
||||
if (-1 === $lineno) { |
||||
$lineno = $this->guessTemplateLine($trace); |
||||
} |
||||
|
||||
if (null === $filename) { |
||||
$filename = $trace['object']->getTemplateName(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
$this->lineno = $lineno; |
||||
$this->filename = $filename; |
||||
$this->rawMessage = $message; |
||||
|
||||
$this->updateRepr(); |
||||
|
||||
if (version_compare(PHP_VERSION, '5.3.0', '<')) { |
||||
$this->previous = $previous; |
||||
parent::__construct($this->message); |
||||
} else { |
||||
parent::__construct($this->message, 0, $previous); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Gets the raw message. |
||||
* |
||||
* @return string The raw message |
||||
*/ |
||||
public function getRawMessage() |
||||
{ |
||||
return $this->rawMessage; |
||||
} |
||||
|
||||
/** |
||||
* Gets the filename where the error occurred. |
||||
* |
||||
* @return string The filename |
||||
*/ |
||||
public function getTemplateFile() |
||||
{ |
||||
return $this->filename; |
||||
} |
||||
|
||||
/** |
||||
* Sets the filename where the error occurred. |
||||
* |
||||
* @param string $filename The filename |
||||
*/ |
||||
public function setTemplateFile($filename) |
||||
{ |
||||
$this->filename = $filename; |
||||
|
||||
$this->updateRepr(); |
||||
} |
||||
|
||||
/** |
||||
* Gets the template line where the error occurred. |
||||
* |
||||
* @return integer The template line |
||||
*/ |
||||
public function getTemplateLine() |
||||
{ |
||||
return $this->lineno; |
||||
} |
||||
|
||||
/** |
||||
* Sets the template line where the error occurred. |
||||
* |
||||
* @param integer $lineno The template line |
||||
*/ |
||||
public function setTemplateLine($lineno) |
||||
{ |
||||
$this->lineno = $lineno; |
||||
|
||||
$this->updateRepr(); |
||||
} |
||||
|
||||
/** |
||||
* For PHP < 5.3.0, provides access to the getPrevious() method. |
||||
* |
||||
* @param string $method The method name |
||||
* @param array $arguments The parameters to be passed to the method |
||||
* |
||||
* @return Exception The previous exception or null |
||||
*/ |
||||
public function __call($method, $arguments) |
||||
{ |
||||
if ('getprevious' == strtolower($method)) { |
||||
return $this->previous; |
||||
} |
||||
|
||||
throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method)); |
||||
} |
||||
|
||||
protected function updateRepr() |
||||
{ |
||||
$this->message = $this->rawMessage; |
||||
|
||||
$dot = false; |
||||
if ('.' === substr($this->message, -1)) { |
||||
$this->message = substr($this->message, 0, -1); |
||||
$dot = true; |
||||
} |
||||
|
||||
if (null !== $this->filename) { |
||||
$this->message .= sprintf(' in %s', is_string($this->filename) ? '"'.$this->filename.'"' : json_encode($this->filename)); |
||||
} |
||||
|
||||
if ($this->lineno >= 0) { |
||||
$this->message .= sprintf(' at line %d', $this->lineno); |
||||
} |
||||
|
||||
if ($dot) { |
||||
$this->message .= '.'; |
||||
} |
||||
} |
||||
|
||||
protected function getTemplateTrace() |
||||
{ |
||||
foreach (debug_backtrace() as $trace) { |
||||
if (isset($trace['object']) && $trace['object'] instanceof Twig_Template) { |
||||
return $trace; |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected function guessTemplateLine($trace) |
||||
{ |
||||
if (isset($trace['line'])) { |
||||
foreach ($trace['object']->getDebugInfo() as $codeLine => $templateLine) { |
||||
if ($codeLine <= $trace['line']) { |
||||
return $templateLine; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
} |
@ -0,0 +1,20 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Exception thrown when an error occurs during template loading. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Error_Loader extends Twig_Error |
||||
{ |
||||
} |
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Exception thrown when an error occurs at runtime. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Error_Runtime extends Twig_Error |
||||
{ |
||||
} |
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Exception thrown when a syntax error occurs during lexing or parsing of a template. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Error_Syntax extends Twig_Error |
||||
{ |
||||
} |
@ -0,0 +1,488 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Parses expressions. |
||||
* |
||||
* This parser implements a "Precedence climbing" algorithm. |
||||
* |
||||
* @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm |
||||
* @see http://en.wikipedia.org/wiki/Operator-precedence_parser |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_ExpressionParser |
||||
{ |
||||
const OPERATOR_LEFT = 1; |
||||
const OPERATOR_RIGHT = 2; |
||||
|
||||
protected $parser; |
||||
protected $unaryOperators; |
||||
protected $binaryOperators; |
||||
|
||||
public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators) |
||||
{ |
||||
$this->parser = $parser; |
||||
$this->unaryOperators = $unaryOperators; |
||||
$this->binaryOperators = $binaryOperators; |
||||
} |
||||
|
||||
public function parseExpression($precedence = 0) |
||||
{ |
||||
$expr = $this->getPrimary(); |
||||
$token = $this->parser->getCurrentToken(); |
||||
while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) { |
||||
$op = $this->binaryOperators[$token->getValue()]; |
||||
$this->parser->getStream()->next(); |
||||
|
||||
if (isset($op['callable'])) { |
||||
$expr = call_user_func($op['callable'], $this->parser, $expr); |
||||
} else { |
||||
$expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']); |
||||
$class = $op['class']; |
||||
$expr = new $class($expr, $expr1, $token->getLine()); |
||||
} |
||||
|
||||
$token = $this->parser->getCurrentToken(); |
||||
} |
||||
|
||||
if (0 === $precedence) { |
||||
return $this->parseConditionalExpression($expr); |
||||
} |
||||
|
||||
return $expr; |
||||
} |
||||
|
||||
protected function getPrimary() |
||||
{ |
||||
$token = $this->parser->getCurrentToken(); |
||||
|
||||
if ($this->isUnary($token)) { |
||||
$operator = $this->unaryOperators[$token->getValue()]; |
||||
$this->parser->getStream()->next(); |
||||
$expr = $this->parseExpression($operator['precedence']); |
||||
$class = $operator['class']; |
||||
|
||||
return $this->parsePostfixExpression(new $class($expr, $token->getLine())); |
||||
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) { |
||||
$this->parser->getStream()->next(); |
||||
$expr = $this->parseExpression(); |
||||
$this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed'); |
||||
|
||||
return $this->parsePostfixExpression($expr); |
||||
} |
||||
|
||||
return $this->parsePrimaryExpression(); |
||||
} |
||||
|
||||
protected function parseConditionalExpression($expr) |
||||
{ |
||||
while ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '?')) { |
||||
$this->parser->getStream()->next(); |
||||
$expr2 = $this->parseExpression(); |
||||
$this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'The ternary operator must have a default value'); |
||||
$expr3 = $this->parseExpression(); |
||||
|
||||
$expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine()); |
||||
} |
||||
|
||||
return $expr; |
||||
} |
||||
|
||||
protected function isUnary(Twig_Token $token) |
||||
{ |
||||
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]); |
||||
} |
||||
|
||||
protected function isBinary(Twig_Token $token) |
||||
{ |
||||
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]); |
||||
} |
||||
|
||||
public function parsePrimaryExpression() |
||||
{ |
||||
$token = $this->parser->getCurrentToken(); |
||||
switch ($token->getType()) { |
||||
case Twig_Token::NAME_TYPE: |
||||
$this->parser->getStream()->next(); |
||||
switch ($token->getValue()) { |
||||
case 'true': |
||||
case 'TRUE': |
||||
$node = new Twig_Node_Expression_Constant(true, $token->getLine()); |
||||
break; |
||||
|
||||
case 'false': |
||||
case 'FALSE': |
||||
$node = new Twig_Node_Expression_Constant(false, $token->getLine()); |
||||
break; |
||||
|
||||
case 'none': |
||||
case 'NONE': |
||||
case 'null': |
||||
case 'NULL': |
||||
$node = new Twig_Node_Expression_Constant(null, $token->getLine()); |
||||
break; |
||||
|
||||
default: |
||||
if ('(' === $this->parser->getCurrentToken()->getValue()) { |
||||
$node = $this->getFunctionNode($token->getValue(), $token->getLine()); |
||||
} else { |
||||
$node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine()); |
||||
} |
||||
} |
||||
break; |
||||
|
||||
case Twig_Token::NUMBER_TYPE: |
||||
$this->parser->getStream()->next(); |
||||
$node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); |
||||
break; |
||||
|
||||
case Twig_Token::STRING_TYPE: |
||||
case Twig_Token::INTERPOLATION_START_TYPE: |
||||
$node = $this->parseStringExpression(); |
||||
break; |
||||
|
||||
default: |
||||
if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) { |
||||
$node = $this->parseArrayExpression(); |
||||
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) { |
||||
$node = $this->parseHashExpression(); |
||||
} else { |
||||
throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine()); |
||||
} |
||||
} |
||||
|
||||
return $this->parsePostfixExpression($node); |
||||
} |
||||
|
||||
public function parseStringExpression() |
||||
{ |
||||
$stream = $this->parser->getStream(); |
||||
|
||||
$nodes = array(); |
||||
// a string cannot be followed by another string in a single expression |
||||
$nextCanBeString = true; |
||||
while (true) { |
||||
if ($stream->test(Twig_Token::STRING_TYPE) && $nextCanBeString) { |
||||
$token = $stream->next(); |
||||
$nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); |
||||
$nextCanBeString = false; |
||||
} elseif ($stream->test(Twig_Token::INTERPOLATION_START_TYPE)) { |
||||
$stream->next(); |
||||
$nodes[] = $this->parseExpression(); |
||||
$stream->expect(Twig_Token::INTERPOLATION_END_TYPE); |
||||
$nextCanBeString = true; |
||||
} else { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
$expr = array_shift($nodes); |
||||
foreach ($nodes as $node) { |
||||
$expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine()); |
||||
} |
||||
|
||||
return $expr; |
||||
} |
||||
|
||||
public function parseArrayExpression() |
||||
{ |
||||
$stream = $this->parser->getStream(); |
||||
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected'); |
||||
|
||||
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine()); |
||||
$first = true; |
||||
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { |
||||
if (!$first) { |
||||
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma'); |
||||
|
||||
// trailing ,? |
||||
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { |
||||
break; |
||||
} |
||||
} |
||||
$first = false; |
||||
|
||||
$node->addElement($this->parseExpression()); |
||||
} |
||||
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed'); |
||||
|
||||
return $node; |
||||
} |
||||
|
||||
public function parseHashExpression() |
||||
{ |
||||
$stream = $this->parser->getStream(); |
||||
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected'); |
||||
|
||||
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine()); |
||||
$first = true; |
||||
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) { |
||||
if (!$first) { |
||||
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma'); |
||||
|
||||
// trailing ,? |
||||
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) { |
||||
break; |
||||
} |
||||
} |
||||
$first = false; |
||||
|
||||
// a hash key can be: |
||||
// |
||||
// * a number -- 12 |
||||
// * a string -- 'a' |
||||
// * a name, which is equivalent to a string -- a |
||||
// * 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)) { |
||||
$token = $stream->next(); |
||||
$key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); |
||||
} elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { |
||||
$key = $this->parseExpression(); |
||||
} else { |
||||
$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()); |
||||
} |
||||
|
||||
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)'); |
||||
$value = $this->parseExpression(); |
||||
|
||||
$node->addElement($value, $key); |
||||
} |
||||
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed'); |
||||
|
||||
return $node; |
||||
} |
||||
|
||||
public function parsePostfixExpression($node) |
||||
{ |
||||
while (true) { |
||||
$token = $this->parser->getCurrentToken(); |
||||
if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) { |
||||
if ('.' == $token->getValue() || '[' == $token->getValue()) { |
||||
$node = $this->parseSubscriptExpression($node); |
||||
} elseif ('|' == $token->getValue()) { |
||||
$node = $this->parseFilterExpression($node); |
||||
} else { |
||||
break; |
||||
} |
||||
} else { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return $node; |
||||
} |
||||
|
||||
public function getFunctionNode($name, $line) |
||||
{ |
||||
$args = $this->parseArguments(); |
||||
switch ($name) { |
||||
case 'parent': |
||||
if (!count($this->parser->getBlockStack())) { |
||||
throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line); |
||||
} |
||||
|
||||
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); |
||||
} |
||||
|
||||
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line); |
||||
case 'block': |
||||
return new Twig_Node_Expression_BlockReference($args->getNode(0), false, $line); |
||||
case 'attribute': |
||||
if (count($args) < 2) { |
||||
throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line); |
||||
} |
||||
|
||||
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_TemplateInterface::ANY_CALL, $line); |
||||
default: |
||||
if (null !== $alias = $this->parser->getImportedFunction($name)) { |
||||
$arguments = new Twig_Node_Expression_Array(array(), $line); |
||||
foreach ($args as $n) { |
||||
$arguments->addElement($n); |
||||
} |
||||
|
||||
$node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line); |
||||
$node->setAttribute('safe', true); |
||||
|
||||
return $node; |
||||
} |
||||
|
||||
$class = $this->getFunctionNodeClass($name); |
||||
|
||||
return new $class($name, $args, $line); |
||||
} |
||||
} |
||||
|
||||
public function parseSubscriptExpression($node) |
||||
{ |
||||
$stream = $this->parser->getStream(); |
||||
$token = $stream->next(); |
||||
$lineno = $token->getLine(); |
||||
$arguments = new Twig_Node_Expression_Array(array(), $lineno); |
||||
$type = Twig_TemplateInterface::ANY_CALL; |
||||
if ($token->getValue() == '.') { |
||||
$token = $stream->next(); |
||||
if ( |
||||
$token->getType() == Twig_Token::NAME_TYPE |
||||
|| |
||||
$token->getType() == Twig_Token::NUMBER_TYPE |
||||
|| |
||||
($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue())) |
||||
) { |
||||
$arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno); |
||||
|
||||
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { |
||||
$type = Twig_TemplateInterface::METHOD_CALL; |
||||
foreach ($this->parseArguments() as $n) { |
||||
$arguments->addElement($n); |
||||
} |
||||
} |
||||
} else { |
||||
throw new Twig_Error_Syntax('Expected name or number', $lineno); |
||||
} |
||||
} else { |
||||
$type = Twig_TemplateInterface::ARRAY_CALL; |
||||
|
||||
$arg = $this->parseExpression(); |
||||
|
||||
// slice? |
||||
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { |
||||
$stream->next(); |
||||
|
||||
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { |
||||
$length = new Twig_Node_Expression_Constant(null, $token->getLine()); |
||||
} else { |
||||
$length = $this->parseExpression(); |
||||
} |
||||
|
||||
$class = $this->getFilterNodeClass('slice'); |
||||
$arguments = new Twig_Node(array($arg, $length)); |
||||
$filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine()); |
||||
|
||||
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); |
||||
|
||||
return $filter; |
||||
} |
||||
|
||||
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); |
||||
} |
||||
|
||||
return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno); |
||||
} |
||||
|
||||
public function parseFilterExpression($node) |
||||
{ |
||||
$this->parser->getStream()->next(); |
||||
|
||||
return $this->parseFilterExpressionRaw($node); |
||||
} |
||||
|
||||
public function parseFilterExpressionRaw($node, $tag = null) |
||||
{ |
||||
while (true) { |
||||
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE); |
||||
|
||||
$name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); |
||||
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) { |
||||
$arguments = new Twig_Node(); |
||||
} else { |
||||
$arguments = $this->parseArguments(); |
||||
} |
||||
|
||||
$class = $this->getFilterNodeClass($name->getAttribute('value')); |
||||
|
||||
$node = new $class($node, $name, $arguments, $token->getLine(), $tag); |
||||
|
||||
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) { |
||||
break; |
||||
} |
||||
|
||||
$this->parser->getStream()->next(); |
||||
} |
||||
|
||||
return $node; |
||||
} |
||||
|
||||
public function parseArguments() |
||||
{ |
||||
$args = array(); |
||||
$stream = $this->parser->getStream(); |
||||
|
||||
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must be opened by a parenthesis'); |
||||
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) { |
||||
if (!empty($args)) { |
||||
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma'); |
||||
} |
||||
$args[] = $this->parseExpression(); |
||||
} |
||||
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis'); |
||||
|
||||
return new Twig_Node($args); |
||||
} |
||||
|
||||
public function parseAssignmentExpression() |
||||
{ |
||||
$targets = array(); |
||||
while (true) { |
||||
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to'); |
||||
if (in_array($token->getValue(), array('true', 'false', 'none'))) { |
||||
throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine()); |
||||
} |
||||
$targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine()); |
||||
|
||||
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) { |
||||
break; |
||||
} |
||||
$this->parser->getStream()->next(); |
||||
} |
||||
|
||||
return new Twig_Node($targets); |
||||
} |
||||
|
||||
public function parseMultitargetExpression() |
||||
{ |
||||
$targets = array(); |
||||
while (true) { |
||||
$targets[] = $this->parseExpression(); |
||||
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) { |
||||
break; |
||||
} |
||||
$this->parser->getStream()->next(); |
||||
} |
||||
|
||||
return new Twig_Node($targets); |
||||
} |
||||
|
||||
protected function getFunctionNodeClass($name) |
||||
{ |
||||
$functionMap = $this->parser->getEnvironment()->getFunctions(); |
||||
if (isset($functionMap[$name]) && $functionMap[$name] instanceof Twig_Function_Node) { |
||||
return $functionMap[$name]->getClass(); |
||||
} |
||||
|
||||
return 'Twig_Node_Expression_Function'; |
||||
} |
||||
|
||||
protected function getFilterNodeClass($name) |
||||
{ |
||||
$filterMap = $this->parser->getEnvironment()->getFilters(); |
||||
if (isset($filterMap[$name]) && $filterMap[$name] instanceof Twig_Filter_Node) { |
||||
return $filterMap[$name]->getClass(); |
||||
} |
||||
|
||||
return 'Twig_Node_Expression_Filter'; |
||||
} |
||||
} |
@ -0,0 +1,93 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
abstract class Twig_Extension implements Twig_ExtensionInterface |
||||
{ |
||||
/** |
||||
* Initializes the runtime environment. |
||||
* |
||||
* 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) |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* 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() |
||||
{ |
||||
return array(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the node visitor instances to add to the existing list. |
||||
* |
||||
* @return array An array of Twig_NodeVisitorInterface instances |
||||
*/ |
||||
public function getNodeVisitors() |
||||
{ |
||||
return array(); |
||||
} |
||||
|
||||
/** |
||||
* Returns a list of filters to add to the existing list. |
||||
* |
||||
* @return array An array of filters |
||||
*/ |
||||
public function getFilters() |
||||
{ |
||||
return array(); |
||||
} |
||||
|
||||
/** |
||||
* Returns a list of tests to add to the existing list. |
||||
* |
||||
* @return array An array of tests |
||||
*/ |
||||
public function getTests() |
||||
{ |
||||
return array(); |
||||
} |
||||
|
||||
/** |
||||
* Returns a list of functions to add to the existing list. |
||||
* |
||||
* @return array An array of functions |
||||
*/ |
||||
public function getFunctions() |
||||
{ |
||||
return array(); |
||||
} |
||||
|
||||
/** |
||||
* Returns a list of operators to add to the existing list. |
||||
* |
||||
* @return array An array of operators |
||||
*/ |
||||
public function getOperators() |
||||
{ |
||||
return array(); |
||||
} |
||||
|
||||
/** |
||||
* Returns a list of global variables to add to the existing list. |
||||
* |
||||
* @return array An array of global variables |
||||
*/ |
||||
public function getGlobals() |
||||
{ |
||||
return array(); |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,64 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_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() |
||||
{ |
||||
// dump is safe if var_dump is overriden by xdebug |
||||
$isDumpOutputHtmlSafe = extension_loaded('xdebug') && (false === get_cfg_var('xdebug.overload_var_dump') || get_cfg_var('xdebug.overload_var_dump')) && get_cfg_var('html_errors'); |
||||
|
||||
return array( |
||||
'dump' => new Twig_Function_Function('twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)), |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* Returns the name of the extension. |
||||
* |
||||
* @return string The extension name |
||||
*/ |
||||
public function getName() |
||||
{ |
||||
return 'debug'; |
||||
} |
||||
} |
||||
|
||||
function twig_var_dump(Twig_Environment $env, $context) |
||||
{ |
||||
if (!$env->isDebug()) { |
||||
return; |
||||
} |
||||
|
||||
ob_start(); |
||||
|
||||
$count = func_num_args(); |
||||
if (2 === $count) { |
||||
$vars = array(); |
||||
foreach ($context as $key => $value) { |
||||
if (!$value instanceof Twig_Template) { |
||||
$vars[$key] = $value; |
||||
} |
||||
} |
||||
|
||||
var_dump($vars); |
||||
} else { |
||||
for ($i = 2; $i < $count; $i++) { |
||||
var_dump(func_get_arg($i)); |
||||
} |
||||
} |
||||
|
||||
return ob_get_clean(); |
||||
} |
@ -0,0 +1,77 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Extension_Escaper extends Twig_Extension |
||||
{ |
||||
protected $autoescape; |
||||
|
||||
public function __construct($autoescape = true) |
||||
{ |
||||
$this->autoescape = $autoescape; |
||||
} |
||||
|
||||
/** |
||||
* 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() |
||||
{ |
||||
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() |
||||
{ |
||||
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() |
||||
{ |
||||
return array( |
||||
'raw' => new Twig_Filter_Function('twig_raw_filter', array('is_safe' => array('all'))), |
||||
); |
||||
} |
||||
|
||||
public function isGlobal() |
||||
{ |
||||
return $this->autoescape; |
||||
} |
||||
|
||||
/** |
||||
* Returns the name of the extension. |
||||
* |
||||
* @return string The extension name |
||||
*/ |
||||
public function getName() |
||||
{ |
||||
return 'escaper'; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Marks a variable as being safe. |
||||
* |
||||
* @param string $string A PHP variable |
||||
*/ |
||||
function twig_raw_filter($string) |
||||
{ |
||||
return $string; |
||||
} |
||||
|
@ -0,0 +1,35 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Extension_Optimizer extends Twig_Extension |
||||
{ |
||||
protected $optimizers; |
||||
|
||||
public function __construct($optimizers = -1) |
||||
{ |
||||
$this->optimizers = $optimizers; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public function getNodeVisitors() |
||||
{ |
||||
return array(new Twig_NodeVisitor_Optimizer($this->optimizers)); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public function getName() |
||||
{ |
||||
return 'optimizer'; |
||||
} |
||||
} |
@ -0,0 +1,112 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Extension_Sandbox extends Twig_Extension |
||||
{ |
||||
protected $sandboxedGlobally; |
||||
protected $sandboxed; |
||||
protected $policy; |
||||
|
||||
public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false) |
||||
{ |
||||
$this->policy = $policy; |
||||
$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() |
||||
{ |
||||
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() |
||||
{ |
||||
return array(new Twig_NodeVisitor_Sandbox()); |
||||
} |
||||
|
||||
public function enableSandbox() |
||||
{ |
||||
$this->sandboxed = true; |
||||
} |
||||
|
||||
public function disableSandbox() |
||||
{ |
||||
$this->sandboxed = false; |
||||
} |
||||
|
||||
public function isSandboxed() |
||||
{ |
||||
return $this->sandboxedGlobally || $this->sandboxed; |
||||
} |
||||
|
||||
public function isSandboxedGlobally() |
||||
{ |
||||
return $this->sandboxedGlobally; |
||||
} |
||||
|
||||
public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy) |
||||
{ |
||||
$this->policy = $policy; |
||||
} |
||||
|
||||
public function getSecurityPolicy() |
||||
{ |
||||
return $this->policy; |
||||
} |
||||
|
||||
public function checkSecurity($tags, $filters, $functions) |
||||
{ |
||||
if ($this->isSandboxed()) { |
||||
$this->policy->checkSecurity($tags, $filters, $functions); |
||||
} |
||||
} |
||||
|
||||
public function checkMethodAllowed($obj, $method) |
||||
{ |
||||
if ($this->isSandboxed()) { |
||||
$this->policy->checkMethodAllowed($obj, $method); |
||||
} |
||||
} |
||||
|
||||
public function checkPropertyAllowed($obj, $method) |
||||
{ |
||||
if ($this->isSandboxed()) { |
||||
$this->policy->checkPropertyAllowed($obj, $method); |
||||
} |
||||
} |
||||
|
||||
public function ensureToStringAllowed($obj) |
||||
{ |
||||
if (is_object($obj)) { |
||||
$this->policy->checkMethodAllowed($obj, '__toString'); |
||||
} |
||||
|
||||
return $obj; |
||||
} |
||||
|
||||
/** |
||||
* Returns the name of the extension. |
||||
* |
||||
* @return string The extension name |
||||
*/ |
||||
public function getName() |
||||
{ |
||||
return 'sandbox'; |
||||
} |
||||
} |
@ -0,0 +1,84 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Interface implemented by extension classes. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
interface Twig_ExtensionInterface |
||||
{ |
||||
/** |
||||
* Initializes the runtime environment. |
||||
* |
||||
* This is where you can load some file that contains filter functions for instance. |
||||
* |
||||
* @param Twig_Environment $environment The current Twig_Environment instance |
||||
*/ |
||||
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 |
||||
*/ |
||||
function getTokenParsers(); |
||||
|
||||
/** |
||||
* Returns the node visitor instances to add to the existing list. |
||||
* |
||||
* @return array An array of Twig_NodeVisitorInterface instances |
||||
*/ |
||||
function getNodeVisitors(); |
||||
|
||||
/** |
||||
* Returns a list of filters to add to the existing list. |
||||
* |
||||
* @return array An array of filters |
||||
*/ |
||||
function getFilters(); |
||||
|
||||
/** |
||||
* Returns a list of tests to add to the existing list. |
||||
* |
||||
* @return array An array of tests |
||||
*/ |
||||
function getTests(); |
||||
|
||||
/** |
||||
* Returns a list of functions to add to the existing list. |
||||
* |
||||
* @return array An array of functions |
||||
*/ |
||||
function getFunctions(); |
||||
|
||||
/** |
||||
* Returns a list of operators to add to the existing list. |
||||
* |
||||
* @return array An array of operators |
||||
*/ |
||||
function getOperators(); |
||||
|
||||
/** |
||||
* Returns a list of global variables to add to the existing list. |
||||
* |
||||
* @return array An array of global variables |
||||
*/ |
||||
function getGlobals(); |
||||
|
||||
/** |
||||
* Returns the name of the extension. |
||||
* |
||||
* @return string The extension name |
||||
*/ |
||||
function getName(); |
||||
} |
@ -0,0 +1,69 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a template filter. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
abstract class Twig_Filter implements Twig_FilterInterface |
||||
{ |
||||
protected $options; |
||||
protected $arguments = array(); |
||||
|
||||
public function __construct(array $options = array()) |
||||
{ |
||||
$this->options = array_merge(array( |
||||
'needs_environment' => false, |
||||
'needs_context' => false, |
||||
'pre_escape' => null, |
||||
), $options); |
||||
} |
||||
|
||||
public function setArguments($arguments) |
||||
{ |
||||
$this->arguments = $arguments; |
||||
} |
||||
|
||||
public function getArguments() |
||||
{ |
||||
return $this->arguments; |
||||
} |
||||
|
||||
public function needsEnvironment() |
||||
{ |
||||
return $this->options['needs_environment']; |
||||
} |
||||
|
||||
public function needsContext() |
||||
{ |
||||
return $this->options['needs_context']; |
||||
} |
||||
|
||||
public function getSafe(Twig_Node $filterArgs) |
||||
{ |
||||
if (isset($this->options['is_safe'])) { |
||||
return $this->options['is_safe']; |
||||
} |
||||
|
||||
if (isset($this->options['is_safe_callback'])) { |
||||
return call_user_func($this->options['is_safe_callback'], $filterArgs); |
||||
} |
||||
|
||||
return array(); |
||||
} |
||||
|
||||
public function getPreEscape() |
||||
{ |
||||
return $this->options['pre_escape']; |
||||
} |
||||
} |
@ -0,0 +1,33 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a function template filter. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Filter_Function extends Twig_Filter |
||||
{ |
||||
protected $function; |
||||
|
||||
public function __construct($function, array $options = array()) |
||||
{ |
||||
parent::__construct($options); |
||||
|
||||
$this->function = $function; |
||||
} |
||||
|
||||
public function compile() |
||||
{ |
||||
return $this->function; |
||||
} |
||||
} |
@ -0,0 +1,34 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a method template filter. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Filter_Method extends Twig_Filter |
||||
{ |
||||
protected $extension, $method; |
||||
|
||||
public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) |
||||
{ |
||||
parent::__construct($options); |
||||
|
||||
$this->extension = $extension; |
||||
$this->method = $method; |
||||
} |
||||
|
||||
public function compile() |
||||
{ |
||||
return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a template filter as a node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Filter_Node extends Twig_Filter |
||||
{ |
||||
protected $class; |
||||
|
||||
public function __construct($class, array $options = array()) |
||||
{ |
||||
parent::__construct($options); |
||||
|
||||
$this->class = $class; |
||||
} |
||||
|
||||
public function getClass() |
||||
{ |
||||
return $this->class; |
||||
} |
||||
|
||||
public function compile() |
||||
{ |
||||
} |
||||
} |
@ -0,0 +1,38 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a template filter. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
interface Twig_FilterInterface |
||||
{ |
||||
/** |
||||
* Compiles a filter. |
||||
* |
||||
* @return string The PHP code for the filter |
||||
*/ |
||||
function compile(); |
||||
|
||||
function needsEnvironment(); |
||||
|
||||
function needsContext(); |
||||
|
||||
function getSafe(Twig_Node $filterArgs); |
||||
|
||||
function getPreEscape(); |
||||
|
||||
function setArguments($arguments); |
||||
|
||||
function getArguments(); |
||||
} |
@ -0,0 +1,63 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a template function. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
abstract class Twig_Function implements Twig_FunctionInterface |
||||
{ |
||||
protected $options; |
||||
protected $arguments = array(); |
||||
|
||||
public function __construct(array $options = array()) |
||||
{ |
||||
$this->options = array_merge(array( |
||||
'needs_environment' => false, |
||||
'needs_context' => false, |
||||
), $options); |
||||
} |
||||
|
||||
public function setArguments($arguments) |
||||
{ |
||||
$this->arguments = $arguments; |
||||
} |
||||
|
||||
public function getArguments() |
||||
{ |
||||
return $this->arguments; |
||||
} |
||||
|
||||
public function needsEnvironment() |
||||
{ |
||||
return $this->options['needs_environment']; |
||||
} |
||||
|
||||
public function needsContext() |
||||
{ |
||||
return $this->options['needs_context']; |
||||
} |
||||
|
||||
public function getSafe(Twig_Node $functionArgs) |
||||
{ |
||||
if (isset($this->options['is_safe'])) { |
||||
return $this->options['is_safe']; |
||||
} |
||||
|
||||
if (isset($this->options['is_safe_callback'])) { |
||||
return call_user_func($this->options['is_safe_callback'], $functionArgs); |
||||
} |
||||
|
||||
return array(); |
||||
} |
||||
} |
@ -0,0 +1,34 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2010 Arnaud Le Blanc |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a function template function. |
||||
* |
||||
* @package twig |
||||
* @author Arnaud Le Blanc <arnaud.lb@gmail.com> |
||||
*/ |
||||
class Twig_Function_Function extends Twig_Function |
||||
{ |
||||
protected $function; |
||||
|
||||
public function __construct($function, array $options = array()) |
||||
{ |
||||
parent::__construct($options); |
||||
|
||||
$this->function = $function; |
||||
} |
||||
|
||||
public function compile() |
||||
{ |
||||
return $this->function; |
||||
} |
||||
} |
@ -0,0 +1,35 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2010 Arnaud Le Blanc |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a method template function. |
||||
* |
||||
* @package twig |
||||
* @author Arnaud Le Blanc <arnaud.lb@gmail.com> |
||||
*/ |
||||
class Twig_Function_Method extends Twig_Function |
||||
{ |
||||
protected $extension, $method; |
||||
|
||||
public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) |
||||
{ |
||||
parent::__construct($options); |
||||
|
||||
$this->extension = $extension; |
||||
$this->method = $method; |
||||
} |
||||
|
||||
public function compile() |
||||
{ |
||||
return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a template function as a node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Function_Node extends Twig_Filter |
||||
{ |
||||
protected $class; |
||||
|
||||
public function __construct($class, array $options = array()) |
||||
{ |
||||
parent::__construct($options); |
||||
|
||||
$this->class = $class; |
||||
} |
||||
|
||||
public function getClass() |
||||
{ |
||||
return $this->class; |
||||
} |
||||
|
||||
public function compile() |
||||
{ |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 Fabien Potencier |
||||
* (c) 2010 Arnaud Le Blanc |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a template function. |
||||
* |
||||
* @package twig |
||||
* @author Arnaud Le Blanc <arnaud.lb@gmail.com> |
||||
*/ |
||||
interface Twig_FunctionInterface |
||||
{ |
||||
/** |
||||
* Compiles a function. |
||||
* |
||||
* @return string The PHP code for the function |
||||
*/ |
||||
function compile(); |
||||
|
||||
function needsEnvironment(); |
||||
|
||||
function needsContext(); |
||||
|
||||
function getSafe(Twig_Node $filterArgs); |
||||
|
||||
function setArguments($arguments); |
||||
|
||||
function getArguments(); |
||||
} |
@ -0,0 +1,406 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Lexes a template string. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Lexer implements Twig_LexerInterface |
||||
{ |
||||
protected $tokens; |
||||
protected $code; |
||||
protected $cursor; |
||||
protected $lineno; |
||||
protected $end; |
||||
protected $state; |
||||
protected $states; |
||||
protected $brackets; |
||||
protected $env; |
||||
protected $filename; |
||||
protected $options; |
||||
protected $regexes; |
||||
|
||||
const STATE_DATA = 0; |
||||
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 REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A'; |
||||
const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As'; |
||||
const REGEX_DQ_STRING_DELIM = '/"/A'; |
||||
const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As'; |
||||
const PUNCTUATION = '()[]{}?:.,|'; |
||||
|
||||
public function __construct(Twig_Environment $env, array $options = array()) |
||||
{ |
||||
$this->env = $env; |
||||
|
||||
$this->options = array_merge(array( |
||||
'tag_comment' => array('{#', '#}'), |
||||
'tag_block' => array('{%', '%}'), |
||||
'tag_variable' => array('{{', '}}'), |
||||
'whitespace_trim' => '-', |
||||
'interpolation' => array('#{', '}'), |
||||
), $options); |
||||
|
||||
$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_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*endraw\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(), |
||||
'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\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_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_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A', |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* 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 (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) { |
||||
$mbEncoding = mb_internal_encoding(); |
||||
mb_internal_encoding('ASCII'); |
||||
} |
||||
|
||||
$this->code = str_replace(array("\r\n", "\r"), "\n", $code); |
||||
$this->filename = $filename; |
||||
$this->cursor = 0; |
||||
$this->lineno = 1; |
||||
$this->end = strlen($this->code); |
||||
$this->tokens = array(); |
||||
$this->state = self::STATE_DATA; |
||||
$this->states = array(); |
||||
$this->brackets = array(); |
||||
$this->position = -1; |
||||
|
||||
// find all token starts in one go |
||||
preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE); |
||||
$this->positions = $matches; |
||||
|
||||
while ($this->cursor < $this->end) { |
||||
// dispatch to the lexing functions depending |
||||
// on the current state |
||||
switch ($this->state) { |
||||
case self::STATE_DATA: |
||||
$this->lexData(); |
||||
break; |
||||
|
||||
case self::STATE_BLOCK: |
||||
$this->lexBlock(); |
||||
break; |
||||
|
||||
case self::STATE_VAR: |
||||
$this->lexVar(); |
||||
break; |
||||
|
||||
case self::STATE_STRING: |
||||
$this->lexString(); |
||||
break; |
||||
|
||||
case self::STATE_INTERPOLATION: |
||||
$this->lexInterpolation(); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
$this->pushToken(Twig_Token::EOF_TYPE); |
||||
|
||||
if (!empty($this->brackets)) { |
||||
list($expect, $lineno) = array_pop($this->brackets); |
||||
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); |
||||
} |
||||
|
||||
if (isset($mbEncoding)) { |
||||
mb_internal_encoding($mbEncoding); |
||||
} |
||||
|
||||
return new Twig_TokenStream($this->tokens, $this->filename); |
||||
} |
||||
|
||||
protected function lexData() |
||||
{ |
||||
// if no matches are left we return the rest of the template as simple text token |
||||
if ($this->position == count($this->positions[0]) - 1) { |
||||
$this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor)); |
||||
$this->cursor = $this->end; |
||||
|
||||
return; |
||||
} |
||||
|
||||
// Find the first token after the current cursor |
||||
$position = $this->positions[0][++$this->position]; |
||||
while ($position[1] < $this->cursor) { |
||||
if ($this->position == count($this->positions[0]) - 1) { |
||||
return; |
||||
} |
||||
$position = $this->positions[0][++$this->position]; |
||||
} |
||||
|
||||
// push the template text first |
||||
$text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor); |
||||
if (isset($this->positions[2][$this->position][0])) { |
||||
$text = rtrim($text); |
||||
} |
||||
$this->pushToken(Twig_Token::TEXT_TYPE, $text); |
||||
$this->moveCursor($textContent.$position[0]); |
||||
|
||||
switch ($this->positions[1][$this->position][0]) { |
||||
case $this->options['tag_comment'][0]: |
||||
$this->lexComment(); |
||||
break; |
||||
|
||||
case $this->options['tag_block'][0]: |
||||
// raw data? |
||||
if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) { |
||||
$this->moveCursor($match[0]); |
||||
$this->lexRawData(); |
||||
// {% line \d+ %} |
||||
} elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) { |
||||
$this->moveCursor($match[0]); |
||||
$this->lineno = (int) $match[1]; |
||||
} else { |
||||
$this->pushToken(Twig_Token::BLOCK_START_TYPE); |
||||
$this->pushState(self::STATE_BLOCK); |
||||
} |
||||
break; |
||||
|
||||
case $this->options['tag_variable'][0]: |
||||
$this->pushToken(Twig_Token::VAR_START_TYPE); |
||||
$this->pushState(self::STATE_VAR); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
protected function lexBlock() |
||||
{ |
||||
if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) { |
||||
$this->pushToken(Twig_Token::BLOCK_END_TYPE); |
||||
$this->moveCursor($match[0]); |
||||
$this->popState(); |
||||
} else { |
||||
$this->lexExpression(); |
||||
} |
||||
} |
||||
|
||||
protected function lexVar() |
||||
{ |
||||
if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) { |
||||
$this->pushToken(Twig_Token::VAR_END_TYPE); |
||||
$this->moveCursor($match[0]); |
||||
$this->popState(); |
||||
} else { |
||||
$this->lexExpression(); |
||||
} |
||||
} |
||||
|
||||
protected function lexExpression() |
||||
{ |
||||
// whitespace |
||||
if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) { |
||||
$this->moveCursor($match[0]); |
||||
|
||||
if ($this->cursor >= $this->end) { |
||||
throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable')); |
||||
} |
||||
} |
||||
|
||||
// operators |
||||
if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) { |
||||
$this->pushToken(Twig_Token::OPERATOR_TYPE, $match[0]); |
||||
$this->moveCursor($match[0]); |
||||
} |
||||
// names |
||||
elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) { |
||||
$this->pushToken(Twig_Token::NAME_TYPE, $match[0]); |
||||
$this->moveCursor($match[0]); |
||||
} |
||||
// numbers |
||||
elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) { |
||||
$number = (float) $match[0]; // floats |
||||
if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) { |
||||
$number = (int) $match[0]; // integers lower than the maximum |
||||
} |
||||
$this->pushToken(Twig_Token::NUMBER_TYPE, $number); |
||||
$this->moveCursor($match[0]); |
||||
} |
||||
// punctuation |
||||
elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) { |
||||
// opening bracket |
||||
if (false !== strpos('([{', $this->code[$this->cursor])) { |
||||
$this->brackets[] = array($this->code[$this->cursor], $this->lineno); |
||||
} |
||||
// closing bracket |
||||
elseif (false !== strpos(')]}', $this->code[$this->cursor])) { |
||||
if (empty($this->brackets)) { |
||||
throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename); |
||||
} |
||||
|
||||
list($expect, $lineno) = array_pop($this->brackets); |
||||
if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) { |
||||
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); |
||||
} |
||||
} |
||||
|
||||
$this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]); |
||||
++$this->cursor; |
||||
} |
||||
// strings |
||||
elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) { |
||||
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1))); |
||||
$this->moveCursor($match[0]); |
||||
} |
||||
// opening double quoted string |
||||
elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) { |
||||
$this->brackets[] = array('"', $this->lineno); |
||||
$this->pushState(self::STATE_STRING); |
||||
$this->moveCursor($match[0]); |
||||
} |
||||
// unlexable |
||||
else { |
||||
throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename); |
||||
} |
||||
} |
||||
|
||||
protected function lexRawData() |
||||
{ |
||||
if (!preg_match($this->regexes['lex_raw_data'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { |
||||
throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "block"')); |
||||
} |
||||
|
||||
$text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor); |
||||
$this->moveCursor($text.$match[0][0]); |
||||
|
||||
if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) { |
||||
$text = rtrim($text); |
||||
} |
||||
|
||||
$this->pushToken(Twig_Token::TEXT_TYPE, $text); |
||||
} |
||||
|
||||
protected function lexComment() |
||||
{ |
||||
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); |
||||
} |
||||
|
||||
$this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]); |
||||
} |
||||
|
||||
protected function lexString() |
||||
{ |
||||
if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) { |
||||
$this->brackets[] = array($this->options['interpolation'][0], $this->lineno); |
||||
$this->pushToken(Twig_Token::INTERPOLATION_START_TYPE); |
||||
$this->moveCursor($match[0]); |
||||
$this->pushState(self::STATE_INTERPOLATION); |
||||
|
||||
} 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->moveCursor($match[0]); |
||||
|
||||
} elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) { |
||||
|
||||
list($expect, $lineno) = array_pop($this->brackets); |
||||
if ($this->code[$this->cursor] != '"') { |
||||
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); |
||||
} |
||||
|
||||
$this->popState(); |
||||
++$this->cursor; |
||||
|
||||
return; |
||||
} |
||||
} |
||||
|
||||
protected function lexInterpolation() |
||||
{ |
||||
$bracket = end($this->brackets); |
||||
if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) { |
||||
array_pop($this->brackets); |
||||
$this->pushToken(Twig_Token::INTERPOLATION_END_TYPE); |
||||
$this->moveCursor($match[0]); |
||||
$this->popState(); |
||||
} else { |
||||
$this->lexExpression(); |
||||
} |
||||
} |
||||
|
||||
protected function pushToken($type, $value = '') |
||||
{ |
||||
// do not push empty text tokens |
||||
if (Twig_Token::TEXT_TYPE === $type && '' === $value) { |
||||
return; |
||||
} |
||||
|
||||
$this->tokens[] = new Twig_Token($type, $value, $this->lineno); |
||||
} |
||||
|
||||
protected function moveCursor($text) |
||||
{ |
||||
$this->cursor += strlen($text); |
||||
$this->lineno += substr_count($text, "\n"); |
||||
} |
||||
|
||||
protected function getOperatorRegex() |
||||
{ |
||||
$operators = array_merge( |
||||
array('='), |
||||
array_keys($this->env->getUnaryOperators()), |
||||
array_keys($this->env->getBinaryOperators()) |
||||
); |
||||
|
||||
$operators = array_combine($operators, array_map('strlen', $operators)); |
||||
arsort($operators); |
||||
|
||||
$regex = array(); |
||||
foreach ($operators as $operator => $length) { |
||||
// an operator that ends with a character must be followed by |
||||
// a whitespace or a parenthesis |
||||
if (ctype_alpha($operator[$length - 1])) { |
||||
$regex[] = preg_quote($operator, '/').'(?=[\s()])'; |
||||
} else { |
||||
$regex[] = preg_quote($operator, '/'); |
||||
} |
||||
} |
||||
|
||||
return '/'.implode('|', $regex).'/A'; |
||||
} |
||||
|
||||
protected function pushState($state) |
||||
{ |
||||
$this->states[] = $this->state; |
||||
$this->state = $state; |
||||
} |
||||
|
||||
protected function popState() |
||||
{ |
||||
if (0 === count($this->states)) { |
||||
throw new Exception('Cannot pop state without a previous state'); |
||||
} |
||||
|
||||
$this->state = array_pop($this->states); |
||||
} |
||||
} |
@ -0,0 +1,29 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Interface implemented by lexer classes. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
interface Twig_LexerInterface |
||||
{ |
||||
/** |
||||
* 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 |
||||
*/ |
||||
function tokenize($code, $filename = null); |
||||
} |
@ -0,0 +1,102 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Loads a template from an array. |
||||
* |
||||
* 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 |
||||
* 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. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Loader_Array implements Twig_LoaderInterface |
||||
{ |
||||
protected $templates; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* |
||||
* @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) |
||||
{ |
||||
$this->templates = array(); |
||||
foreach ($templates as $name => $template) { |
||||
$this->templates[$name] = $template; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Adds or overrides a template. |
||||
* |
||||
* @param string $name The template name |
||||
* @param string $template The template source |
||||
*/ |
||||
public function setTemplate($name, $template) |
||||
{ |
||||
$this->templates[(string) $name] = $template; |
||||
} |
||||
|
||||
/** |
||||
* Gets the source code of a template, given its name. |
||||
* |
||||
* @param string $name The name of the template to load |
||||
* |
||||
* @return string The template source code |
||||
*/ |
||||
public function getSource($name) |
||||
{ |
||||
$name = (string) $name; |
||||
if (!isset($this->templates[$name])) { |
||||
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); |
||||
} |
||||
|
||||
return $this->templates[$name]; |
||||
} |
||||
|
||||
/** |
||||
* Gets the cache key to use for the cache for a given template name. |
||||
* |
||||
* @param string $name The name of the template to load |
||||
* |
||||
* @return string The cache key |
||||
*/ |
||||
public function getCacheKey($name) |
||||
{ |
||||
$name = (string) $name; |
||||
if (!isset($this->templates[$name])) { |
||||
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); |
||||
} |
||||
|
||||
return $this->templates[$name]; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the template is still fresh. |
||||
* |
||||
* @param string $name The template name |
||||
* @param timestamp $time The last modification time of the cached template |
||||
*/ |
||||
public function isFresh($name, $time) |
||||
{ |
||||
$name = (string) $name; |
||||
if (!isset($this->templates[$name])) { |
||||
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,100 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Loads templates from other loaders. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Loader_Chain implements Twig_LoaderInterface |
||||
{ |
||||
protected $loaders; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* |
||||
* @param Twig_LoaderInterface[] $loaders An array of loader instances |
||||
*/ |
||||
public function __construct(array $loaders = array()) |
||||
{ |
||||
$this->loaders = array(); |
||||
foreach ($loaders as $loader) { |
||||
$this->addLoader($loader); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Adds a loader instance. |
||||
* |
||||
* @param Twig_LoaderInterface $loader A Loader instance |
||||
*/ |
||||
public function addLoader(Twig_LoaderInterface $loader) |
||||
{ |
||||
$this->loaders[] = $loader; |
||||
} |
||||
|
||||
/** |
||||
* Gets the source code of a template, given its name. |
||||
* |
||||
* @param string $name The name of the template to load |
||||
* |
||||
* @return string The template source code |
||||
*/ |
||||
public function getSource($name) |
||||
{ |
||||
foreach ($this->loaders as $loader) { |
||||
try { |
||||
return $loader->getSource($name); |
||||
} catch (Twig_Error_Loader $e) { |
||||
} |
||||
} |
||||
|
||||
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); |
||||
} |
||||
|
||||
/** |
||||
* Gets the cache key to use for the cache for a given template name. |
||||
* |
||||
* @param string $name The name of the template to load |
||||
* |
||||
* @return string The cache key |
||||
*/ |
||||
public function getCacheKey($name) |
||||
{ |
||||
foreach ($this->loaders as $loader) { |
||||
try { |
||||
return $loader->getCacheKey($name); |
||||
} catch (Twig_Error_Loader $e) { |
||||
} |
||||
} |
||||
|
||||
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the template is still fresh. |
||||
* |
||||
* @param string $name The template name |
||||
* @param timestamp $time The last modification time of the cached template |
||||
*/ |
||||
public function isFresh($name, $time) |
||||
{ |
||||
foreach ($this->loaders as $loader) { |
||||
try { |
||||
return $loader->isFresh($name, $time); |
||||
} catch (Twig_Error_Loader $e) { |
||||
} |
||||
} |
||||
|
||||
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); |
||||
} |
||||
} |
@ -0,0 +1,152 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Loads template from the filesystem. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Loader_Filesystem implements Twig_LoaderInterface |
||||
{ |
||||
protected $paths; |
||||
protected $cache; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* |
||||
* @param string|array $paths A path or an array of paths where to look for templates |
||||
*/ |
||||
public function __construct($paths) |
||||
{ |
||||
$this->setPaths($paths); |
||||
} |
||||
|
||||
/** |
||||
* Returns the paths to the templates. |
||||
* |
||||
* @return array The array of paths where to look for templates |
||||
*/ |
||||
public function getPaths() |
||||
{ |
||||
return $this->paths; |
||||
} |
||||
|
||||
/** |
||||
* Sets the paths where templates are stored. |
||||
* |
||||
* @param string|array $paths A path or an array of paths where to look for templates |
||||
*/ |
||||
public function setPaths($paths) |
||||
{ |
||||
if (!is_array($paths)) { |
||||
$paths = array($paths); |
||||
} |
||||
|
||||
$this->paths = array(); |
||||
foreach ($paths as $path) { |
||||
$this->addPath($path); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Adds a path where templates are stored. |
||||
* |
||||
* @param string $path A path where to look for templates |
||||
*/ |
||||
public function addPath($path) |
||||
{ |
||||
// invalidate the cache |
||||
$this->cache = array(); |
||||
|
||||
if (!is_dir($path)) { |
||||
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path)); |
||||
} |
||||
|
||||
$this->paths[] = $path; |
||||
} |
||||
|
||||
/** |
||||
* Gets the source code of a template, given its name. |
||||
* |
||||
* @param string $name The name of the template to load |
||||
* |
||||
* @return string The template source code |
||||
*/ |
||||
public function getSource($name) |
||||
{ |
||||
return file_get_contents($this->findTemplate($name)); |
||||
} |
||||
|
||||
/** |
||||
* Gets the cache key to use for the cache for a given template name. |
||||
* |
||||
* @param string $name The name of the template to load |
||||
* |
||||
* @return string The cache key |
||||
*/ |
||||
public function getCacheKey($name) |
||||
{ |
||||
return $this->findTemplate($name); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the template is still fresh. |
||||
* |
||||
* @param string $name The template name |
||||
* @param timestamp $time The last modification time of the cached template |
||||
*/ |
||||
public function isFresh($name, $time) |
||||
{ |
||||
return filemtime($this->findTemplate($name)) < $time; |
||||
} |
||||
|
||||
protected function findTemplate($name) |
||||
{ |
||||
// normalize name |
||||
$name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/')); |
||||
|
||||
if (isset($this->cache[$name])) { |
||||
return $this->cache[$name]; |
||||
} |
||||
|
||||
$this->validateName($name); |
||||
|
||||
foreach ($this->paths as $path) { |
||||
if (is_file($path.'/'.$name)) { |
||||
return $this->cache[$name] = $path.'/'.$name; |
||||
} |
||||
} |
||||
|
||||
throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths))); |
||||
} |
||||
|
||||
protected function validateName($name) |
||||
{ |
||||
if (false !== strpos($name, "\0")) { |
||||
throw new Twig_Error_Loader('A template name cannot contain NUL bytes.'); |
||||
} |
||||
|
||||
$parts = explode('/', $name); |
||||
$level = 0; |
||||
foreach ($parts as $part) { |
||||
if ('..' === $part) { |
||||
--$level; |
||||
} elseif ('.' !== $part) { |
||||
++$level; |
||||
} |
||||
|
||||
if ($level < 0) { |
||||
throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name)); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,59 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Loads a template from a string. |
||||
* |
||||
* 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 |
||||
* 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. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Loader_String implements Twig_LoaderInterface |
||||
{ |
||||
/** |
||||
* Gets the source code of a template, given its name. |
||||
* |
||||
* @param string $name The name of the template to load |
||||
* |
||||
* @return string The template source code |
||||
*/ |
||||
public function getSource($name) |
||||
{ |
||||
return $name; |
||||
} |
||||
|
||||
/** |
||||
* Gets the cache key to use for the cache for a given template name. |
||||
* |
||||
* @param string $name The name of the template to load |
||||
* |
||||
* @return string The cache key |
||||
*/ |
||||
public function getCacheKey($name) |
||||
{ |
||||
return $name; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the template is still fresh. |
||||
* |
||||
* @param string $name The template name |
||||
* @param timestamp $time The last modification time of the cached template |
||||
*/ |
||||
public function isFresh($name, $time) |
||||
{ |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,53 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Interface all loaders must implement. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
interface Twig_LoaderInterface |
||||
{ |
||||
/** |
||||
* Gets the source code of a template, given its name. |
||||
* |
||||
* @param string $name The name of the template to load |
||||
* |
||||
* @return string The template source code |
||||
* |
||||
* @throws Twig_Error_Loader When $name is not found |
||||
*/ |
||||
function getSource($name); |
||||
|
||||
/** |
||||
* Gets the cache key to use for the cache for a given template name. |
||||
* |
||||
* @param string $name The name of the template to load |
||||
* |
||||
* @return string The cache key |
||||
* |
||||
* @throws Twig_Error_Loader When $name is not found |
||||
*/ |
||||
function getCacheKey($name); |
||||
|
||||
/** |
||||
* Returns true if the template is still fresh. |
||||
* |
||||
* @param string $name The template name |
||||
* @param timestamp $time The last modification time of the cached template |
||||
* |
||||
* @return Boolean true if the template is fresh, false otherwise |
||||
* |
||||
* @throws Twig_Error_Loader When $name is not found |
||||
*/ |
||||
function isFresh($name, $time); |
||||
} |
@ -0,0 +1,38 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Marks a content as safe. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Markup implements Countable |
||||
{ |
||||
protected $content; |
||||
protected $charset; |
||||
|
||||
public function __construct($content, $charset) |
||||
{ |
||||
$this->content = (string) $content; |
||||
$this->charset = $charset; |
||||
} |
||||
|
||||
public function __toString() |
||||
{ |
||||
return $this->content; |
||||
} |
||||
|
||||
public function count() |
||||
{ |
||||
return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content); |
||||
} |
||||
} |
@ -0,0 +1,227 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a node in the AST. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node implements Twig_NodeInterface |
||||
{ |
||||
protected $nodes; |
||||
protected $attributes; |
||||
protected $lineno; |
||||
protected $tag; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* |
||||
* The nodes are automatically made available as properties ($this->node). |
||||
* The attributes are automatically made available as array items ($this['name']). |
||||
* |
||||
* @param array $nodes An array of named nodes |
||||
* @param array $attributes An array of attributes (should not be nodes) |
||||
* @param integer $lineno The line number |
||||
* @param string $tag The tag name associated with the Node |
||||
*/ |
||||
public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null) |
||||
{ |
||||
$this->nodes = $nodes; |
||||
$this->attributes = $attributes; |
||||
$this->lineno = $lineno; |
||||
$this->tag = $tag; |
||||
} |
||||
|
||||
public function __toString() |
||||
{ |
||||
$attributes = array(); |
||||
foreach ($this->attributes as $name => $value) { |
||||
$attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true))); |
||||
} |
||||
|
||||
$repr = array(get_class($this).'('.implode(', ', $attributes)); |
||||
|
||||
if (count($this->nodes)) { |
||||
foreach ($this->nodes as $name => $node) { |
||||
$len = strlen($name) + 4; |
||||
$noderepr = array(); |
||||
foreach (explode("\n", (string) $node) as $line) { |
||||
$noderepr[] = str_repeat(' ', $len).$line; |
||||
} |
||||
|
||||
$repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr))); |
||||
} |
||||
|
||||
$repr[] = ')'; |
||||
} else { |
||||
$repr[0] .= ')'; |
||||
} |
||||
|
||||
return implode("\n", $repr); |
||||
} |
||||
|
||||
public function toXml($asDom = false) |
||||
{ |
||||
$dom = new DOMDocument('1.0', 'UTF-8'); |
||||
$dom->formatOutput = true; |
||||
$dom->appendChild($xml = $dom->createElement('twig')); |
||||
|
||||
$xml->appendChild($node = $dom->createElement('node')); |
||||
$node->setAttribute('class', get_class($this)); |
||||
|
||||
foreach ($this->attributes as $name => $value) { |
||||
$node->appendChild($attribute = $dom->createElement('attribute')); |
||||
$attribute->setAttribute('name', $name); |
||||
$attribute->appendChild($dom->createTextNode($value)); |
||||
} |
||||
|
||||
foreach ($this->nodes as $name => $n) { |
||||
if (null === $n) { |
||||
continue; |
||||
} |
||||
|
||||
$child = $n->toXml(true)->getElementsByTagName('node')->item(0); |
||||
$child = $dom->importNode($child, true); |
||||
$child->setAttribute('name', $name); |
||||
|
||||
$node->appendChild($child); |
||||
} |
||||
|
||||
return $asDom ? $dom : $dom->saveXml(); |
||||
} |
||||
|
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
foreach ($this->nodes as $node) { |
||||
$node->compile($compiler); |
||||
} |
||||
} |
||||
|
||||
public function getLine() |
||||
{ |
||||
return $this->lineno; |
||||
} |
||||
|
||||
public function getNodeTag() |
||||
{ |
||||
return $this->tag; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the attribute is defined. |
||||
* |
||||
* @param string The attribute name |
||||
* |
||||
* @return Boolean true if the attribute is defined, false otherwise |
||||
*/ |
||||
public function hasAttribute($name) |
||||
{ |
||||
return array_key_exists($name, $this->attributes); |
||||
} |
||||
|
||||
/** |
||||
* Gets an attribute. |
||||
* |
||||
* @param string The attribute name |
||||
* |
||||
* @return mixed The attribute value |
||||
*/ |
||||
public function getAttribute($name) |
||||
{ |
||||
if (!array_key_exists($name, $this->attributes)) { |
||||
throw new Twig_Error_Runtime(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this))); |
||||
} |
||||
|
||||
return $this->attributes[$name]; |
||||
} |
||||
|
||||
/** |
||||
* Sets an attribute. |
||||
* |
||||
* @param string The attribute name |
||||
* @param mixed The attribute value |
||||
*/ |
||||
public function setAttribute($name, $value) |
||||
{ |
||||
$this->attributes[$name] = $value; |
||||
} |
||||
|
||||
/** |
||||
* Removes an attribute. |
||||
* |
||||
* @param string The attribute name |
||||
*/ |
||||
public function removeAttribute($name) |
||||
{ |
||||
unset($this->attributes[$name]); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the node with the given identifier exists. |
||||
* |
||||
* @param string The node name |
||||
* |
||||
* @return Boolean true if the node with the given name exists, false otherwise |
||||
*/ |
||||
public function hasNode($name) |
||||
{ |
||||
return array_key_exists($name, $this->nodes); |
||||
} |
||||
|
||||
/** |
||||
* Gets a node by name. |
||||
* |
||||
* @param string The node name |
||||
* |
||||
* @return Twig_Node A Twig_Node instance |
||||
*/ |
||||
public function getNode($name) |
||||
{ |
||||
if (!array_key_exists($name, $this->nodes)) { |
||||
throw new Twig_Error_Runtime(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this))); |
||||
} |
||||
|
||||
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) |
||||
{ |
||||
$this->nodes[$name] = $node; |
||||
} |
||||
|
||||
/** |
||||
* Removes a node by name. |
||||
* |
||||
* @param string The node name |
||||
*/ |
||||
public function removeNode($name) |
||||
{ |
||||
unset($this->nodes[$name]); |
||||
} |
||||
|
||||
public function count() |
||||
{ |
||||
return count($this->nodes); |
||||
} |
||||
|
||||
public function getIterator() |
||||
{ |
||||
return new ArrayIterator($this->nodes); |
||||
} |
||||
} |
@ -0,0 +1,40 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents an autoescape node. |
||||
* |
||||
* The value is the escaping strategy (can be html, js, ...) |
||||
* |
||||
* The true value is equivalent to html. |
||||
* |
||||
* If autoescaping is disabled, then the value is false. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_AutoEscape extends Twig_Node |
||||
{ |
||||
public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape') |
||||
{ |
||||
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) |
||||
{ |
||||
$compiler->subcompile($this->getNode('body')); |
||||
} |
||||
} |
@ -0,0 +1,45 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a block node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Block extends Twig_Node |
||||
{ |
||||
public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null) |
||||
{ |
||||
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) |
||||
{ |
||||
$compiler |
||||
->addDebugInfo($this) |
||||
->write(sprintf("public function block_%s(\$context, array \$blocks = array())\n", $this->getAttribute('name')), "{\n") |
||||
->indent() |
||||
; |
||||
|
||||
$compiler |
||||
->subcompile($this->getNode('body')) |
||||
->outdent() |
||||
->write("}\n\n") |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,38 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a block call node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInterface |
||||
{ |
||||
public function __construct($name, $lineno, $tag = null) |
||||
{ |
||||
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) |
||||
{ |
||||
$compiler |
||||
->addDebugInfo($this) |
||||
->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name'))) |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,20 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a body node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Body extends Twig_Node |
||||
{ |
||||
} |
@ -0,0 +1,39 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a do node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Do extends Twig_Node |
||||
{ |
||||
public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null) |
||||
{ |
||||
parent::__construct(array('expr' => $expr), array(), $lineno, $tag); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->addDebugInfo($this) |
||||
->write('') |
||||
->subcompile($this->getNode('expr')) |
||||
->raw(";\n") |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Abstract class for all nodes that represents an expression. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
abstract class Twig_Node_Expression extends Twig_Node |
||||
{ |
||||
} |
@ -0,0 +1,86 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 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_Array extends Twig_Node_Expression |
||||
{ |
||||
protected $index; |
||||
|
||||
public function __construct(array $elements, $lineno) |
||||
{ |
||||
parent::__construct($elements, array(), $lineno); |
||||
|
||||
$this->index = -1; |
||||
foreach ($this->getKeyValuePairs() as $pair) { |
||||
if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) { |
||||
$this->index = $pair['key']->getAttribute('value'); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public function getKeyValuePairs() |
||||
{ |
||||
$pairs = array(); |
||||
|
||||
foreach (array_chunk($this->nodes, 2) as $pair) { |
||||
$pairs[] = array( |
||||
'key' => $pair[0], |
||||
'value' => $pair[1], |
||||
); |
||||
} |
||||
|
||||
return $pairs; |
||||
} |
||||
|
||||
public function hasElement(Twig_Node_Expression $key) |
||||
{ |
||||
foreach ($this->getKeyValuePairs() as $pair) { |
||||
// we compare the string representation of the keys |
||||
// to avoid comparing the line numbers which are not relevant here. |
||||
if ((string) $key == (string) $pair['key']) { |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null) |
||||
{ |
||||
if (null === $key) { |
||||
$key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine()); |
||||
} |
||||
|
||||
array_push($this->nodes, $key, $value); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->raw('array('); |
||||
$first = true; |
||||
foreach ($this->getKeyValuePairs() as $pair) { |
||||
if (!$first) { |
||||
$compiler->raw(', '); |
||||
} |
||||
$first = false; |
||||
|
||||
$compiler |
||||
->subcompile($pair['key']) |
||||
->raw(' => ') |
||||
->subcompile($pair['value']) |
||||
; |
||||
} |
||||
$compiler->raw(')'); |
||||
} |
||||
} |
@ -0,0 +1,28 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
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) |
||||
{ |
||||
$compiler |
||||
->raw('$context[') |
||||
->string($this->getAttribute('name')) |
||||
->raw(']') |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,40 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression |
||||
{ |
||||
public function __construct(Twig_NodeInterface $left, Twig_NodeInterface $right, $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) |
||||
{ |
||||
$compiler |
||||
->raw('(') |
||||
->subcompile($this->getNode('left')) |
||||
->raw(' ') |
||||
; |
||||
$this->operator($compiler); |
||||
$compiler |
||||
->raw(' ') |
||||
->subcompile($this->getNode('right')) |
||||
->raw(')') |
||||
; |
||||
} |
||||
|
||||
abstract public function operator(Twig_Compiler $compiler); |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Binary_Add extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('+'); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Binary_And extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('&&'); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Binary_BitwiseAnd extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('&'); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Binary_BitwiseOr extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('|'); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Binary_BitwiseXor extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('^'); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Binary_Concat extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('.'); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Binary_Div extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('/'); |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 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_Equal extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('=='); |
||||
} |
||||
} |
@ -0,0 +1,29 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 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_FloorDiv extends Twig_Node_Expression_Binary |
||||
{ |
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->raw('intval(floor('); |
||||
parent::compile($compiler); |
||||
$compiler->raw('))'); |
||||
} |
||||
|
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('/'); |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 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_Greater extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('>'); |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 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_GreaterEqual extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('>='); |
||||
} |
||||
} |
@ -0,0 +1,33 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 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_In extends Twig_Node_Expression_Binary |
||||
{ |
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->raw('twig_in_filter(') |
||||
->subcompile($this->getNode('left')) |
||||
->raw(', ') |
||||
->subcompile($this->getNode('right')) |
||||
->raw(')') |
||||
; |
||||
} |
||||
|
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('in'); |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 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_Less extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('<'); |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 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_LessEqual extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('<='); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Binary_Mod extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('%'); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Binary_Mul extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('*'); |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 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_NotEqual extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('!='); |
||||
} |
||||
} |
@ -0,0 +1,33 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 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_NotIn extends Twig_Node_Expression_Binary |
||||
{ |
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->raw('!twig_in_filter(') |
||||
->subcompile($this->getNode('left')) |
||||
->raw(', ') |
||||
->subcompile($this->getNode('right')) |
||||
->raw(')') |
||||
; |
||||
} |
||||
|
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('not in'); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Binary_Or extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('||'); |
||||
} |
||||
} |
@ -0,0 +1,33 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 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_Power extends Twig_Node_Expression_Binary |
||||
{ |
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->raw('pow(') |
||||
->subcompile($this->getNode('left')) |
||||
->raw(', ') |
||||
->subcompile($this->getNode('right')) |
||||
->raw(')') |
||||
; |
||||
} |
||||
|
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('**'); |
||||
} |
||||
} |
@ -0,0 +1,33 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 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_Range extends Twig_Node_Expression_Binary |
||||
{ |
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->raw('range(') |
||||
->subcompile($this->getNode('left')) |
||||
->raw(', ') |
||||
->subcompile($this->getNode('right')) |
||||
->raw(')') |
||||
; |
||||
} |
||||
|
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('..'); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Binary_Sub extends Twig_Node_Expression_Binary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
return $compiler->raw('-'); |
||||
} |
||||
} |
@ -0,0 +1,52 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a block call node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Expression_BlockReference extends Twig_Node_Expression |
||||
{ |
||||
public function __construct(Twig_NodeInterface $name, $asString = false, $lineno, $tag = null) |
||||
{ |
||||
parent::__construct(array('name' => $name), array('as_string' => $asString, 'output' => false), $lineno, $tag); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
if ($this->getAttribute('as_string')) { |
||||
$compiler->raw('(string) '); |
||||
} |
||||
|
||||
if ($this->getAttribute('output')) { |
||||
$compiler |
||||
->addDebugInfo($this) |
||||
->write("\$this->displayBlock(") |
||||
->subcompile($this->getNode('name')) |
||||
->raw(", \$context, \$blocks);\n") |
||||
; |
||||
} else { |
||||
$compiler |
||||
->raw("\$this->renderBlock(") |
||||
->subcompile($this->getNode('name')) |
||||
->raw(", \$context, \$blocks)") |
||||
; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,31 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Conditional extends Twig_Node_Expression |
||||
{ |
||||
public function __construct(Twig_Node_Expression $expr1, Twig_Node_Expression $expr2, Twig_Node_Expression $expr3, $lineno) |
||||
{ |
||||
parent::__construct(array('expr1' => $expr1, 'expr2' => $expr2, 'expr3' => $expr3), array(), $lineno); |
||||
} |
||||
|
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->raw('((') |
||||
->subcompile($this->getNode('expr1')) |
||||
->raw(') ? (') |
||||
->subcompile($this->getNode('expr2')) |
||||
->raw(') : (') |
||||
->subcompile($this->getNode('expr3')) |
||||
->raw('))') |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,23 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Constant extends Twig_Node_Expression |
||||
{ |
||||
public function __construct($value, $lineno) |
||||
{ |
||||
parent::__construct(array(), array('value' => $value), $lineno); |
||||
} |
||||
|
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->repr($this->getAttribute('value')); |
||||
} |
||||
} |
@ -0,0 +1,34 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents an extension call node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression |
||||
{ |
||||
public function __construct($name, $lineno, $tag = null) |
||||
{ |
||||
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) |
||||
{ |
||||
$compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name'))); |
||||
} |
||||
} |
@ -0,0 +1,61 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Filter extends Twig_Node_Expression |
||||
{ |
||||
public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null) |
||||
{ |
||||
parent::__construct(array('node' => $node, 'filter' => $filterName, 'arguments' => $arguments), array(), $lineno, $tag); |
||||
} |
||||
|
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$name = $this->getNode('filter')->getAttribute('value'); |
||||
|
||||
if (false === $filter = $compiler->getEnvironment()->getFilter($name)) { |
||||
$message = sprintf('The filter "%s" does not exist', $name); |
||||
if ($alternatives = $compiler->getEnvironment()->computeAlternatives($name, array_keys($compiler->getEnvironment()->getFilters()))) { |
||||
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); |
||||
} |
||||
|
||||
throw new Twig_Error_Syntax($message, $this->getLine()); |
||||
} |
||||
|
||||
$this->compileFilter($compiler, $filter); |
||||
} |
||||
|
||||
protected function compileFilter(Twig_Compiler $compiler, Twig_FilterInterface $filter) |
||||
{ |
||||
$compiler |
||||
->raw($filter->compile().'(') |
||||
->raw($filter->needsEnvironment() ? '$this->env, ' : '') |
||||
->raw($filter->needsContext() ? '$context, ' : '') |
||||
; |
||||
|
||||
foreach ($filter->getArguments() as $argument) { |
||||
$compiler |
||||
->string($argument) |
||||
->raw(', ') |
||||
; |
||||
} |
||||
|
||||
$compiler->subcompile($this->getNode('node')); |
||||
|
||||
foreach ($this->getNode('arguments') as $node) { |
||||
$compiler |
||||
->raw(', ') |
||||
->subcompile($node) |
||||
; |
||||
} |
||||
|
||||
$compiler->raw(')'); |
||||
} |
||||
} |
@ -0,0 +1,44 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Returns the value or the default value when it is undefined or empty. |
||||
* |
||||
* <pre> |
||||
* {{ var.foo|default('foo item on var is not defined') }} |
||||
* </pre> |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter |
||||
{ |
||||
public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null) |
||||
{ |
||||
$default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('_default', $node->getLine()), $arguments, $node->getLine()); |
||||
|
||||
if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) { |
||||
$test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine()); |
||||
$false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine()); |
||||
|
||||
$node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine()); |
||||
} else { |
||||
$node = $default; |
||||
} |
||||
|
||||
parent::__construct($node, $filterName, $arguments, $lineno, $tag); |
||||
} |
||||
|
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->subcompile($this->getNode('node')); |
||||
} |
||||
} |
@ -0,0 +1,66 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 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_Function extends Twig_Node_Expression |
||||
{ |
||||
public function __construct($name, Twig_NodeInterface $arguments, $lineno) |
||||
{ |
||||
parent::__construct(array('arguments' => $arguments), array('name' => $name), $lineno); |
||||
} |
||||
|
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$name = $this->getAttribute('name'); |
||||
|
||||
if (false === $function = $compiler->getEnvironment()->getFunction($name)) { |
||||
$message = sprintf('The function "%s" does not exist', $name); |
||||
if ($alternatives = $compiler->getEnvironment()->computeAlternatives($name, array_keys($compiler->getEnvironment()->getFunctions()))) { |
||||
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); |
||||
} |
||||
|
||||
throw new Twig_Error_Syntax($message, $this->getLine()); |
||||
} |
||||
|
||||
$compiler->raw($function->compile().'('); |
||||
|
||||
$first = true; |
||||
|
||||
if ($function->needsEnvironment()) { |
||||
$compiler->raw('$this->env'); |
||||
$first = false; |
||||
} |
||||
|
||||
if ($function->needsContext()) { |
||||
if (!$first) { |
||||
$compiler->raw(', '); |
||||
} |
||||
$compiler->raw('$context'); |
||||
$first = false; |
||||
} |
||||
|
||||
foreach ($function->getArguments() as $argument) { |
||||
if (!$first) { |
||||
$compiler->raw(', '); |
||||
} |
||||
$compiler->string($argument); |
||||
$first = false; |
||||
} |
||||
|
||||
foreach ($this->getNode('arguments') as $node) { |
||||
if (!$first) { |
||||
$compiler->raw(', '); |
||||
} |
||||
$compiler->subcompile($node); |
||||
$first = false; |
||||
} |
||||
|
||||
$compiler->raw(')'); |
||||
} |
||||
} |
@ -0,0 +1,53 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
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) |
||||
{ |
||||
parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false), $lineno); |
||||
} |
||||
|
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
if (function_exists('twig_template_get_attributes')) { |
||||
$compiler->raw('twig_template_get_attributes($this, '); |
||||
} else { |
||||
$compiler->raw('$this->getAttribute('); |
||||
} |
||||
|
||||
if ($this->getAttribute('ignore_strict_check')) { |
||||
$this->getNode('node')->setAttribute('ignore_strict_check', true); |
||||
} |
||||
|
||||
$compiler->subcompile($this->getNode('node')); |
||||
|
||||
$compiler->raw(', ')->subcompile($this->getNode('attribute')); |
||||
|
||||
if (count($this->getNode('arguments')) || Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { |
||||
$compiler->raw(', ')->subcompile($this->getNode('arguments')); |
||||
|
||||
if (Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { |
||||
$compiler->raw(', ')->repr($this->getAttribute('type')); |
||||
} |
||||
|
||||
if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { |
||||
$compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false')); |
||||
} |
||||
|
||||
if ($this->getAttribute('ignore_strict_check')) { |
||||
$compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false')); |
||||
} |
||||
} |
||||
|
||||
$compiler->raw(')'); |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2012 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_MethodCall extends Twig_Node_Expression |
||||
{ |
||||
public function __construct(Twig_Node_Expression $node, $method, Twig_Node_Expression_Array $arguments, $lineno) |
||||
{ |
||||
parent::__construct(array('node' => $node, 'arguments' => $arguments), array('method' => $method, 'safe' => false), $lineno); |
||||
} |
||||
|
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->subcompile($this->getNode('node')) |
||||
->raw('->') |
||||
->raw($this->getAttribute('method')) |
||||
->raw('(') |
||||
; |
||||
$first = true; |
||||
foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) { |
||||
if (!$first) { |
||||
$compiler->raw(', '); |
||||
} |
||||
$first = false; |
||||
|
||||
$compiler->subcompile($pair['value']); |
||||
} |
||||
$compiler->raw(')'); |
||||
} |
||||
} |
@ -0,0 +1,76 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Name extends Twig_Node_Expression |
||||
{ |
||||
protected $specialVars = array( |
||||
'_self' => '$this', |
||||
'_context' => '$context', |
||||
'_charset' => '$this->env->getCharset()', |
||||
); |
||||
|
||||
public function __construct($name, $lineno) |
||||
{ |
||||
parent::__construct(array(), array('name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false), $lineno); |
||||
} |
||||
|
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$name = $this->getAttribute('name'); |
||||
|
||||
if ($this->getAttribute('is_defined_test')) { |
||||
if ($this->isSpecial()) { |
||||
$compiler->repr(true); |
||||
} else { |
||||
$compiler->raw('array_key_exists(')->repr($name)->raw(', $context)'); |
||||
} |
||||
} elseif ($this->isSpecial()) { |
||||
$compiler->raw($this->specialVars[$name]); |
||||
} else { |
||||
// remove the non-PHP 5.4 version when PHP 5.3 support is dropped |
||||
// as the non-optimized version is just a workaround for slow ternary operator |
||||
// when the context has a lot of variables |
||||
if (version_compare(phpversion(), '5.4.0RC1', '>=') && ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables())) { |
||||
// PHP 5.4 ternary operator performance was optimized |
||||
$compiler |
||||
->raw('(isset($context[') |
||||
->string($name) |
||||
->raw(']) ? $context[') |
||||
->string($name) |
||||
->raw('] : null)') |
||||
; |
||||
} else { |
||||
$compiler |
||||
->raw('$this->getContext($context, ') |
||||
->string($name) |
||||
; |
||||
|
||||
if ($this->getAttribute('ignore_strict_check')) { |
||||
$compiler->raw(', true'); |
||||
} |
||||
|
||||
$compiler |
||||
->raw(')') |
||||
; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public function isSpecial() |
||||
{ |
||||
return isset($this->specialVars[$this->getAttribute('name')]); |
||||
} |
||||
|
||||
public function isSimple() |
||||
{ |
||||
return !$this->isSpecial() && !$this->getAttribute('is_defined_test'); |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a parent node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Expression_Parent extends Twig_Node_Expression |
||||
{ |
||||
public function __construct($name, $lineno, $tag = null) |
||||
{ |
||||
parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
if ($this->getAttribute('output')) { |
||||
$compiler |
||||
->addDebugInfo($this) |
||||
->write("\$this->displayParentBlock(") |
||||
->string($this->getAttribute('name')) |
||||
->raw(", \$context, \$blocks);\n") |
||||
; |
||||
} else { |
||||
$compiler |
||||
->raw("\$this->renderParentBlock(") |
||||
->string($this->getAttribute('name')) |
||||
->raw(", \$context, \$blocks)") |
||||
; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,22 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_TempName extends Twig_Node_Expression |
||||
{ |
||||
public function __construct($name, $lineno) |
||||
{ |
||||
parent::__construct(array(), array('name' => $name), $lineno); |
||||
} |
||||
|
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->raw('$_')->raw($this->getAttribute('name'))->raw('_'); |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 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_Test extends Twig_Node_Expression |
||||
{ |
||||
public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno) |
||||
{ |
||||
parent::__construct(array('node' => $node, 'arguments' => $arguments), array('name' => $name), $lineno); |
||||
} |
||||
|
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$name = $this->getAttribute('name'); |
||||
$testMap = $compiler->getEnvironment()->getTests(); |
||||
if (!isset($testMap[$name])) { |
||||
$message = sprintf('The test "%s" does not exist', $name); |
||||
if ($alternatives = $compiler->getEnvironment()->computeAlternatives($name, array_keys($compiler->getEnvironment()->getTests()))) { |
||||
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); |
||||
} |
||||
|
||||
throw new Twig_Error_Syntax($message, $this->getLine()); |
||||
} |
||||
|
||||
$name = $this->getAttribute('name'); |
||||
$node = $this->getNode('node'); |
||||
|
||||
$compiler |
||||
->raw($testMap[$name]->compile().'(') |
||||
->subcompile($node) |
||||
; |
||||
|
||||
if (null !== $this->getNode('arguments')) { |
||||
$compiler->raw(', '); |
||||
|
||||
$max = count($this->getNode('arguments')) - 1; |
||||
foreach ($this->getNode('arguments') as $i => $arg) { |
||||
$compiler->subcompile($arg); |
||||
|
||||
if ($i != $max) { |
||||
$compiler->raw(', '); |
||||
} |
||||
} |
||||
} |
||||
|
||||
$compiler->raw(')'); |
||||
} |
||||
} |
@ -0,0 +1,36 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Checks if a variable is the exact same value as a constant. |
||||
* |
||||
* <pre> |
||||
* {% if post.status is constant('Post::PUBLISHED') %} |
||||
* the status attribute is exactly the same as Post::PUBLISHED |
||||
* {% endif %} |
||||
* </pre> |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test |
||||
{ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->raw('(') |
||||
->subcompile($this->getNode('node')) |
||||
->raw(' === constant(') |
||||
->subcompile($this->getNode('arguments')->getNode(0)) |
||||
->raw('))') |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,55 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Checks if a variable is defined in the current context. |
||||
* |
||||
* <pre> |
||||
* {# defined works with variable names and variable attributes #} |
||||
* {% if foo is defined %} |
||||
* {# ... #} |
||||
* {% endif %} |
||||
* </pre> |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test |
||||
{ |
||||
public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno) |
||||
{ |
||||
parent::__construct($node, $name, $arguments, $lineno); |
||||
|
||||
if ($node instanceof Twig_Node_Expression_Name) { |
||||
$node->setAttribute('is_defined_test', true); |
||||
} elseif ($node instanceof Twig_Node_Expression_GetAttr) { |
||||
$node->setAttribute('is_defined_test', true); |
||||
|
||||
$this->changeIgnoreStrictCheck($node); |
||||
} else { |
||||
throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine()); |
||||
} |
||||
} |
||||
|
||||
protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node) |
||||
{ |
||||
$node->setAttribute('ignore_strict_check', true); |
||||
|
||||
if ($node->getNode('node') instanceof Twig_Node_Expression_GetAttr) { |
||||
$this->changeIgnoreStrictCheck($node->getNode('node')); |
||||
} |
||||
} |
||||
|
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->subcompile($this->getNode('node')); |
||||
} |
||||
} |
@ -0,0 +1,34 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Checks if a variable is divisible by a number. |
||||
* |
||||
* <pre> |
||||
* {% if loop.index is divisibleby(3) %} |
||||
* </pre> |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test |
||||
{ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->raw('(0 == ') |
||||
->subcompile($this->getNode('node')) |
||||
->raw(' % ') |
||||
->subcompile($this->getNode('arguments')->getNode(0)) |
||||
->raw(')') |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,33 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Checks if a number is even. |
||||
* |
||||
* <pre> |
||||
* {{ var is even }} |
||||
* </pre> |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test |
||||
{ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->raw('(') |
||||
->subcompile($this->getNode('node')) |
||||
->raw(' % 2 == 0') |
||||
->raw(')') |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,32 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Checks that a variable is null. |
||||
* |
||||
* <pre> |
||||
* {{ var is none }} |
||||
* </pre> |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test |
||||
{ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->raw('(null === ') |
||||
->subcompile($this->getNode('node')) |
||||
->raw(')') |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,33 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Checks if a number is odd. |
||||
* |
||||
* <pre> |
||||
* {{ var is odd }} |
||||
* </pre> |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test |
||||
{ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->raw('(') |
||||
->subcompile($this->getNode('node')) |
||||
->raw(' % 2 == 1') |
||||
->raw(')') |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,30 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Checks if a variable is the same as another one (=== in PHP). |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test |
||||
{ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->raw('(') |
||||
->subcompile($this->getNode('node')) |
||||
->raw(' === ') |
||||
->subcompile($this->getNode('arguments')->getNode(0)) |
||||
->raw(')') |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,30 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
abstract class Twig_Node_Expression_Unary extends Twig_Node_Expression |
||||
{ |
||||
public function __construct(Twig_NodeInterface $node, $lineno) |
||||
{ |
||||
parent::__construct(array('node' => $node), array(), $lineno); |
||||
} |
||||
|
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->raw('('); |
||||
$this->operator($compiler); |
||||
$compiler |
||||
->subcompile($this->getNode('node')) |
||||
->raw(')') |
||||
; |
||||
} |
||||
|
||||
abstract public function operator(Twig_Compiler $compiler); |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Unary_Neg extends Twig_Node_Expression_Unary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->raw('-'); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Unary_Not extends Twig_Node_Expression_Unary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->raw('!'); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
class Twig_Node_Expression_Unary_Pos extends Twig_Node_Expression_Unary |
||||
{ |
||||
public function operator(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->raw('+'); |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a flush node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Flush extends Twig_Node |
||||
{ |
||||
public function __construct($lineno, $tag) |
||||
{ |
||||
parent::__construct(array(), array(), $lineno, $tag); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->addDebugInfo($this) |
||||
->write("flush();\n") |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,113 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a for node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_For extends Twig_Node |
||||
{ |
||||
protected $loop; |
||||
|
||||
public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_Node_Expression $ifexpr = null, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null) |
||||
{ |
||||
$body = new Twig_Node(array($body, $this->loop = new Twig_Node_ForLoop($lineno, $tag))); |
||||
|
||||
if (null !== $ifexpr) { |
||||
$body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag); |
||||
} |
||||
|
||||
parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body, 'else' => $else), array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->addDebugInfo($this) |
||||
// the (array) cast bypasses a PHP 5.2.6 bug |
||||
->write("\$context['_parent'] = (array) \$context;\n") |
||||
->write("\$context['_seq'] = twig_ensure_traversable(") |
||||
->subcompile($this->getNode('seq')) |
||||
->raw(");\n") |
||||
; |
||||
|
||||
if (null !== $this->getNode('else')) { |
||||
$compiler->write("\$context['_iterated'] = false;\n"); |
||||
} |
||||
|
||||
if ($this->getAttribute('with_loop')) { |
||||
$compiler |
||||
->write("\$context['loop'] = array(\n") |
||||
->write(" 'parent' => \$context['_parent'],\n") |
||||
->write(" 'index0' => 0,\n") |
||||
->write(" 'index' => 1,\n") |
||||
->write(" 'first' => true,\n") |
||||
->write(");\n") |
||||
; |
||||
|
||||
if (!$this->getAttribute('ifexpr')) { |
||||
$compiler |
||||
->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n") |
||||
->indent() |
||||
->write("\$length = count(\$context['_seq']);\n") |
||||
->write("\$context['loop']['revindex0'] = \$length - 1;\n") |
||||
->write("\$context['loop']['revindex'] = \$length;\n") |
||||
->write("\$context['loop']['length'] = \$length;\n") |
||||
->write("\$context['loop']['last'] = 1 === \$length;\n") |
||||
->outdent() |
||||
->write("}\n") |
||||
; |
||||
} |
||||
} |
||||
|
||||
$this->loop->setAttribute('else', null !== $this->getNode('else')); |
||||
$this->loop->setAttribute('with_loop', $this->getAttribute('with_loop')); |
||||
$this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr')); |
||||
|
||||
$compiler |
||||
->write("foreach (\$context['_seq'] as ") |
||||
->subcompile($this->getNode('key_target')) |
||||
->raw(" => ") |
||||
->subcompile($this->getNode('value_target')) |
||||
->raw(") {\n") |
||||
->indent() |
||||
->subcompile($this->getNode('body')) |
||||
->outdent() |
||||
->write("}\n") |
||||
; |
||||
|
||||
if (null !== $this->getNode('else')) { |
||||
$compiler |
||||
->write("if (!\$context['_iterated']) {\n") |
||||
->indent() |
||||
->subcompile($this->getNode('else')) |
||||
->outdent() |
||||
->write("}\n") |
||||
; |
||||
} |
||||
|
||||
$compiler->write("\$_parent = \$context['_parent'];\n"); |
||||
|
||||
// remove some "private" loop variables (needed for nested loops) |
||||
$compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n"); |
||||
|
||||
// keep the values set in the inner context for variables defined in the outer context |
||||
$compiler->write("\$context = array_merge(\$_parent, array_intersect_key(\$context, \$_parent));\n"); |
||||
} |
||||
} |
@ -0,0 +1,56 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2011 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Internal node used by the for node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_ForLoop extends Twig_Node |
||||
{ |
||||
public function __construct($lineno, $tag = null) |
||||
{ |
||||
parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
if ($this->getAttribute('else')) { |
||||
$compiler->write("\$context['_iterated'] = true;\n"); |
||||
} |
||||
|
||||
if ($this->getAttribute('with_loop')) { |
||||
$compiler |
||||
->write("++\$context['loop']['index0'];\n") |
||||
->write("++\$context['loop']['index'];\n") |
||||
->write("\$context['loop']['first'] = false;\n") |
||||
; |
||||
|
||||
if (!$this->getAttribute('ifexpr')) { |
||||
$compiler |
||||
->write("if (isset(\$context['loop']['length'])) {\n") |
||||
->indent() |
||||
->write("--\$context['loop']['revindex0'];\n") |
||||
->write("--\$context['loop']['revindex'];\n") |
||||
->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n") |
||||
->outdent() |
||||
->write("}\n") |
||||
; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,67 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents an if node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_If extends Twig_Node |
||||
{ |
||||
public function __construct(Twig_NodeInterface $tests, Twig_NodeInterface $else = null, $lineno, $tag = null) |
||||
{ |
||||
parent::__construct(array('tests' => $tests, 'else' => $else), array(), $lineno, $tag); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->addDebugInfo($this); |
||||
for ($i = 0; $i < count($this->getNode('tests')); $i += 2) { |
||||
if ($i > 0) { |
||||
$compiler |
||||
->outdent() |
||||
->write("} elseif (") |
||||
; |
||||
} else { |
||||
$compiler |
||||
->write('if (') |
||||
; |
||||
} |
||||
|
||||
$compiler |
||||
->subcompile($this->getNode('tests')->getNode($i)) |
||||
->raw(") {\n") |
||||
->indent() |
||||
->subcompile($this->getNode('tests')->getNode($i + 1)) |
||||
; |
||||
} |
||||
|
||||
if ($this->hasNode('else') && null !== $this->getNode('else')) { |
||||
$compiler |
||||
->outdent() |
||||
->write("} else {\n") |
||||
->indent() |
||||
->subcompile($this->getNode('else')) |
||||
; |
||||
} |
||||
|
||||
$compiler |
||||
->outdent() |
||||
->write("}\n"); |
||||
} |
||||
} |
@ -0,0 +1,51 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents an import node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Import extends Twig_Node |
||||
{ |
||||
public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $var, $lineno, $tag = null) |
||||
{ |
||||
parent::__construct(array('expr' => $expr, 'var' => $var), array(), $lineno, $tag); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->addDebugInfo($this) |
||||
->write('') |
||||
->subcompile($this->getNode('var')) |
||||
->raw(' = ') |
||||
; |
||||
|
||||
if ($this->getNode('expr') instanceof Twig_Node_Expression_Name && '_self' === $this->getNode('expr')->getAttribute('name')) { |
||||
$compiler->raw("\$this"); |
||||
} else { |
||||
$compiler |
||||
->raw('$this->env->loadTemplate(') |
||||
->subcompile($this->getNode('expr')) |
||||
->raw(")") |
||||
; |
||||
} |
||||
|
||||
$compiler->raw(";\n"); |
||||
} |
||||
} |
@ -0,0 +1,88 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents an include node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface |
||||
{ |
||||
public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) |
||||
{ |
||||
parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (Boolean) $only, 'ignore_missing' => (Boolean) $ignoreMissing), $lineno, $tag); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->addDebugInfo($this); |
||||
|
||||
if ($this->getAttribute('ignore_missing')) { |
||||
$compiler |
||||
->write("try {\n") |
||||
->indent() |
||||
; |
||||
} |
||||
|
||||
if ($this->getNode('expr') instanceof Twig_Node_Expression_Constant) { |
||||
$compiler |
||||
->write("\$this->env->loadTemplate(") |
||||
->subcompile($this->getNode('expr')) |
||||
->raw(")->display(") |
||||
; |
||||
} else { |
||||
$compiler |
||||
->write("\$template = \$this->env->resolveTemplate(") |
||||
->subcompile($this->getNode('expr')) |
||||
->raw(");\n") |
||||
->write('$template->display(') |
||||
; |
||||
} |
||||
|
||||
if (false === $this->getAttribute('only')) { |
||||
if (null === $this->getNode('variables')) { |
||||
$compiler->raw('$context'); |
||||
} else { |
||||
$compiler |
||||
->raw('array_merge($context, ') |
||||
->subcompile($this->getNode('variables')) |
||||
->raw(')') |
||||
; |
||||
} |
||||
} else { |
||||
if (null === $this->getNode('variables')) { |
||||
$compiler->raw('array()'); |
||||
} else { |
||||
$compiler->subcompile($this->getNode('variables')); |
||||
} |
||||
} |
||||
|
||||
$compiler->raw(");\n"); |
||||
|
||||
if ($this->getAttribute('ignore_missing')) { |
||||
$compiler |
||||
->outdent() |
||||
->write("} catch (Twig_Error_Loader \$e) {\n") |
||||
->indent() |
||||
->write("// ignore missing template\n") |
||||
->outdent() |
||||
->write("}\n\n") |
||||
; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,84 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a macro node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Macro extends Twig_Node |
||||
{ |
||||
public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null) |
||||
{ |
||||
parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$arguments = array(); |
||||
foreach ($this->getNode('arguments') as $argument) { |
||||
$arguments[] = '$'.$argument->getAttribute('name').' = null'; |
||||
} |
||||
|
||||
$compiler |
||||
->addDebugInfo($this) |
||||
->write(sprintf("public function get%s(%s)\n", $this->getAttribute('name'), implode(', ', $arguments)), "{\n") |
||||
->indent() |
||||
; |
||||
|
||||
if (!count($this->getNode('arguments'))) { |
||||
$compiler->write("\$context = \$this->env->getGlobals();\n\n"); |
||||
} else { |
||||
$compiler |
||||
->write("\$context = array_merge(\$this->env->getGlobals(), array(\n") |
||||
->indent() |
||||
; |
||||
|
||||
foreach ($this->getNode('arguments') as $argument) { |
||||
$compiler |
||||
->write('') |
||||
->string($argument->getAttribute('name')) |
||||
->raw(' => $'.$argument->getAttribute('name')) |
||||
->raw(",\n") |
||||
; |
||||
} |
||||
|
||||
$compiler |
||||
->outdent() |
||||
->write("));\n\n") |
||||
; |
||||
} |
||||
|
||||
$compiler |
||||
->write("\$blocks = array();\n\n") |
||||
->write("ob_start();\n") |
||||
->write("try {\n") |
||||
->indent() |
||||
->subcompile($this->getNode('body')) |
||||
->outdent() |
||||
->write("} catch(Exception \$e) {\n") |
||||
->indent() |
||||
->write("ob_end_clean();\n\n") |
||||
->write("throw \$e;\n") |
||||
->outdent() |
||||
->write("}\n\n") |
||||
->write("return ob_get_clean();\n") |
||||
->outdent() |
||||
->write("}\n\n") |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,358 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a module node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Module extends Twig_Node |
||||
{ |
||||
public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $filename) |
||||
{ |
||||
parent::__construct(array('parent' => $parent, 'body' => $body, 'blocks' => $blocks, 'macros' => $macros, 'traits' => $traits), array('filename' => $filename), 1); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$this->compileTemplate($compiler); |
||||
} |
||||
|
||||
protected function compileTemplate(Twig_Compiler $compiler) |
||||
{ |
||||
$this->compileClassHeader($compiler); |
||||
|
||||
if (count($this->getNode('blocks')) || count($this->getNode('traits'))) { |
||||
$this->compileConstructor($compiler); |
||||
} |
||||
|
||||
$this->compileGetParent($compiler); |
||||
|
||||
$this->compileDisplayHeader($compiler); |
||||
|
||||
$this->compileDisplayBody($compiler); |
||||
|
||||
$this->compileDisplayFooter($compiler); |
||||
|
||||
$compiler->subcompile($this->getNode('blocks')); |
||||
|
||||
$this->compileMacros($compiler); |
||||
|
||||
$this->compileGetTemplateName($compiler); |
||||
|
||||
$this->compileIsTraitable($compiler); |
||||
|
||||
$this->compileDebugInfo($compiler); |
||||
|
||||
$this->compileClassFooter($compiler); |
||||
} |
||||
|
||||
protected function compileGetParent(Twig_Compiler $compiler) |
||||
{ |
||||
if (null === $this->getNode('parent')) { |
||||
return; |
||||
} |
||||
|
||||
$compiler |
||||
->write("protected function doGetParent(array \$context)\n", "{\n") |
||||
->indent() |
||||
->write("return ") |
||||
; |
||||
|
||||
if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) { |
||||
$compiler->subcompile($this->getNode('parent')); |
||||
} else { |
||||
$compiler |
||||
->raw("\$this->env->resolveTemplate(") |
||||
->subcompile($this->getNode('parent')) |
||||
->raw(")") |
||||
; |
||||
} |
||||
|
||||
$compiler |
||||
->raw(";\n") |
||||
->outdent() |
||||
->write("}\n\n") |
||||
; |
||||
} |
||||
|
||||
protected function compileDisplayBody(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->subcompile($this->getNode('body')); |
||||
|
||||
if (null !== $this->getNode('parent')) { |
||||
if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) { |
||||
$compiler->write("\$this->parent"); |
||||
} else { |
||||
$compiler->write("\$this->getParent(\$context)"); |
||||
} |
||||
$compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n"); |
||||
} |
||||
} |
||||
|
||||
protected function compileClassHeader(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->write("<?php\n\n")
|
||||
// if the filename contains */, add a blank to avoid a PHP parse error |
||||
->write("/* ".str_replace('*/', '* /', $this->getAttribute('filename'))." */\n") |
||||
->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'))) |
||||
->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass())) |
||||
->write("{\n") |
||||
->indent() |
||||
; |
||||
} |
||||
|
||||
protected function compileConstructor(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->write("public function __construct(Twig_Environment \$env)\n", "{\n") |
||||
->indent() |
||||
->write("parent::__construct(\$env);\n\n") |
||||
; |
||||
|
||||
// parent |
||||
if (null === $this->getNode('parent')) { |
||||
$compiler->write("\$this->parent = false;\n\n"); |
||||
} elseif ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) { |
||||
$compiler |
||||
->write("\$this->parent = \$this->env->loadTemplate(") |
||||
->subcompile($this->getNode('parent')) |
||||
->raw(");\n\n") |
||||
; |
||||
} |
||||
|
||||
$countTraits = count($this->getNode('traits')); |
||||
if ($countTraits) { |
||||
// traits |
||||
foreach ($this->getNode('traits') as $i => $trait) { |
||||
$this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i)); |
||||
|
||||
$compiler |
||||
->addDebugInfo($trait->getNode('template')) |
||||
->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i)) |
||||
->indent() |
||||
->write("throw new Twig_Error_Runtime('Template \"'.") |
||||
->subcompile($trait->getNode('template')) |
||||
->raw(".'\" cannot be used as a trait.');\n") |
||||
->outdent() |
||||
->write("}\n") |
||||
->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i)) |
||||
; |
||||
|
||||
foreach ($trait->getNode('targets') as $key => $value) { |
||||
$compiler |
||||
->write(sprintf("\$_trait_%s_blocks[", $i)) |
||||
->subcompile($value) |
||||
->raw(sprintf("] = \$_trait_%s_blocks[", $i)) |
||||
->string($key) |
||||
->raw(sprintf("]; unset(\$_trait_%s_blocks[", $i)) |
||||
->string($key) |
||||
->raw("]);\n\n") |
||||
; |
||||
} |
||||
} |
||||
|
||||
if ($countTraits > 1) { |
||||
$compiler |
||||
->write("\$this->traits = array_merge(\n") |
||||
->indent() |
||||
; |
||||
|
||||
for ($i = 0; $i < $countTraits; $i++) { |
||||
$compiler |
||||
->write(sprintf("\$_trait_%s_blocks".($i == $countTraits - 1 ? '' : ',')."\n", $i)) |
||||
; |
||||
} |
||||
|
||||
$compiler |
||||
->outdent() |
||||
->write(");\n\n") |
||||
; |
||||
} else { |
||||
$compiler |
||||
->write("\$this->traits = \$_trait_0_blocks;\n\n") |
||||
; |
||||
} |
||||
|
||||
$compiler |
||||
->write("\$this->blocks = array_merge(\n") |
||||
->indent() |
||||
->write("\$this->traits,\n") |
||||
->write("array(\n") |
||||
; |
||||
} else { |
||||
$compiler |
||||
->write("\$this->blocks = array(\n") |
||||
; |
||||
} |
||||
|
||||
// blocks |
||||
$compiler |
||||
->indent() |
||||
; |
||||
|
||||
foreach ($this->getNode('blocks') as $name => $node) { |
||||
$compiler |
||||
->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name)) |
||||
; |
||||
} |
||||
|
||||
if ($countTraits) { |
||||
$compiler |
||||
->outdent() |
||||
->write(")\n") |
||||
; |
||||
} |
||||
|
||||
$compiler |
||||
->outdent() |
||||
->write(");\n") |
||||
->outdent() |
||||
->write("}\n\n"); |
||||
; |
||||
} |
||||
|
||||
protected function compileDisplayHeader(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n") |
||||
->indent() |
||||
; |
||||
} |
||||
|
||||
protected function compileDisplayFooter(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->outdent() |
||||
->write("}\n\n") |
||||
; |
||||
} |
||||
|
||||
protected function compileClassFooter(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->outdent() |
||||
->write("}\n") |
||||
; |
||||
} |
||||
|
||||
protected function compileMacros(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler->subcompile($this->getNode('macros')); |
||||
} |
||||
|
||||
protected function compileGetTemplateName(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->write("public function getTemplateName()\n", "{\n") |
||||
->indent() |
||||
->write('return ') |
||||
->repr($this->getAttribute('filename')) |
||||
->raw(";\n") |
||||
->outdent() |
||||
->write("}\n\n") |
||||
; |
||||
} |
||||
|
||||
protected function compileIsTraitable(Twig_Compiler $compiler) |
||||
{ |
||||
// A template can be used as a trait if: |
||||
// * it has no parent |
||||
// * it has no macros |
||||
// * it has no body |
||||
// |
||||
// Put another way, a template can be used as a trait if it |
||||
// only contains blocks and use statements. |
||||
$traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros')); |
||||
if ($traitable) { |
||||
if ($this->getNode('body') instanceof Twig_Node_Body) { |
||||
$nodes = $this->getNode('body')->getNode(0); |
||||
} else { |
||||
$nodes = $this->getNode('body'); |
||||
} |
||||
|
||||
if (!count($nodes)) { |
||||
$nodes = new Twig_Node(array($nodes)); |
||||
} |
||||
|
||||
foreach ($nodes as $node) { |
||||
if (!count($node)) { |
||||
continue; |
||||
} |
||||
|
||||
if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) { |
||||
continue; |
||||
} |
||||
|
||||
if ($node instanceof Twig_Node_BlockReference) { |
||||
continue; |
||||
} |
||||
|
||||
$traitable = false; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if ($traitable) { |
||||
return; |
||||
} |
||||
|
||||
$compiler |
||||
->write("public function isTraitable()\n", "{\n") |
||||
->indent() |
||||
->write(sprintf("return %s;\n", $traitable ? 'true' : 'false')) |
||||
->outdent() |
||||
->write("}\n\n") |
||||
; |
||||
} |
||||
|
||||
protected function compileDebugInfo(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->write("public function getDebugInfo()\n", "{\n") |
||||
->indent() |
||||
->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true)))) |
||||
->outdent() |
||||
->write("}\n") |
||||
; |
||||
} |
||||
|
||||
protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var) |
||||
{ |
||||
if ($node instanceof Twig_Node_Expression_Constant) { |
||||
$compiler |
||||
->write(sprintf("%s = \$this->env->loadTemplate(", $var)) |
||||
->subcompile($node) |
||||
->raw(");\n") |
||||
; |
||||
} else { |
||||
$compiler |
||||
->write(sprintf("%s = ", $var)) |
||||
->subcompile($node) |
||||
->raw(";\n") |
||||
->write(sprintf("if (!%s", $var)) |
||||
->raw(" instanceof Twig_Template) {\n") |
||||
->indent() |
||||
->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var)) |
||||
->outdent() |
||||
->write("}\n") |
||||
; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,40 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2009 Fabien Potencier |
||||
* (c) 2009 Armin Ronacher |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a node that outputs an expression. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface |
||||
{ |
||||
public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null) |
||||
{ |
||||
parent::__construct(array('expr' => $expr), array(), $lineno, $tag); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->addDebugInfo($this) |
||||
->write('echo ') |
||||
->subcompile($this->getNode('expr')) |
||||
->raw(";\n") |
||||
; |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
<?php |
||||
|
||||
/* |
||||
* This file is part of Twig. |
||||
* |
||||
* (c) 2010 Fabien Potencier |
||||
* |
||||
* For the full copyright and license information, please view the LICENSE |
||||
* file that was distributed with this source code. |
||||
*/ |
||||
|
||||
/** |
||||
* Represents a sandbox node. |
||||
* |
||||
* @package twig |
||||
* @author Fabien Potencier <fabien@symfony.com> |
||||
*/ |
||||
class Twig_Node_Sandbox extends Twig_Node |
||||
{ |
||||
public function __construct(Twig_NodeInterface $body, $lineno, $tag = null) |
||||
{ |
||||
parent::__construct(array('body' => $body), array(), $lineno, $tag); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the node to PHP. |
||||
* |
||||
* @param Twig_Compiler A Twig_Compiler instance |
||||
*/ |
||||
public function compile(Twig_Compiler $compiler) |
||||
{ |
||||
$compiler |
||||
->addDebugInfo($this) |
||||
->write("\$sandbox = \$this->env->getExtension('sandbox');\n") |
||||
->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n") |
||||
->indent() |
||||
->write("\$sandbox->enableSandbox();\n") |
||||
->outdent() |
||||
->write("}\n") |
||||
->subcompile($this->getNode('body')) |
||||
->write("if (!\$alreadySandboxed) {\n") |
||||
->indent() |
||||
->write("\$sandbox->disableSandbox();\n") |
||||
->outdent() |
||||
->write("}\n") |
||||
; |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue