* 1.11.0 (2012-XX-XX)
+ * optimized the way Twig exceptions are managed (to make them faster)
* added Twig_ExistsLoaderInterface (implementing this interface in your loader make the chain loader much faster)
* 1.10.3 (2012-10-19)
protected $debugInfo;
protected $sourceOffset;
protected $sourceLine;
+ protected $filename;
/**
* Constructor.
$this->debugInfo = array();
}
+ public function getFilename()
+ {
+ return $this->filename;
+ }
+
/**
* Returns the environment instance related to this compiler.
*
$this->sourceLine = 0;
$this->indentation = $indentation;
+ if ($node instanceof Twig_Node_Module) {
+ $this->filename = $node->getAttribute('filename');
+ }
+
$node->compile($this);
return $this;
{
// can't outdent by more steps that the current indentation level
if ($this->indentation < $step) {
- throw new Twig_Error('Unable to call outdent() as the indentation would become negative');
+ throw new LogicException('Unable to call outdent() as the indentation would become negative');
}
$this->indentation -= $step;
} elseif ($parser instanceof Twig_TokenParserBrokerInterface) {
$this->parsers->addTokenParserBroker($parser);
} else {
- throw new Twig_Error_Runtime('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances');
+ throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances');
}
}
}
}
}
- throw new Twig_Error_Runtime(sprintf('Failed to write cache file "%s".', $file));
+ throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file));
}
}
/**
* Twig base exception.
*
+ * This exception class and its children must only be used when
+ * an error occurs during the loading of a template, when a syntax error
+ * is detected in a template, or when rendering a template. Other
+ * errors must use regular PHP exception classes (like when the template
+ * cache directory is not writable for instance).
+ *
+ * To help debugging template issues, this class tracks the original template
+ * name and line where the error occurred.
+ *
+ * Whenever possible, you must set these information (original template name
+ * and line number) yourself by passing them to the constructor. If some or all
+ * these information are not available from where you throw the exception, then
+ * this class will guess them automatically (when the line number is set to -1
+ * and/or the filename is set to null). As this is a costly operation, this
+ * can be disabled by passing false for both the filename and the line number
+ * when creating a new instance of this class.
+ *
* @package twig
* @author Fabien Potencier <fabien@symfony.com>
*/
/**
* Constructor.
*
+ * Set both the line number and the filename to false to
+ * disable automatic guessing of the original template name
+ * and line number.
+ *
+ * Set the line number to -1 to enable its automatic guessing.
+ * Set the filename to null to enable its automatic guessing.
+ *
+ * By default, automatic guessing is enabled.
+ *
* @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
$this->updateRepr();
}
+ public function guess()
+ {
+ $this->guessTemplateInfo();
+ $this->updateRepr();
+ }
+
/**
* For PHP < 5.3.0, provides access to the getPrevious() method.
*
$dot = true;
}
- if (null !== $this->filename) {
+ if ($this->filename) {
if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) {
$filename = sprintf('"%s"', $this->filename);
} else {
$this->message .= sprintf(' in %s', $filename);
}
- if ($this->lineno >= 0) {
+ if ($this->lineno && $this->lineno >= 0) {
$this->message .= sprintf(' at line %d', $this->lineno);
}
/**
* Exception thrown when an error occurs during template loading.
*
+ * Automatic template information guessing is always turned off as
+ * if a template cannot be loaded, there is nothing to guess.
+ * However, when a template is loaded from another one, then, we need
+ * to find the current context and this is automatically done by
+ * Twig_Template::displayWithErrorHandling().
+ *
+ * This strategy makes Twig_Environment::resolveTemplate() much faster.
+ *
* @package twig
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error_Loader extends Twig_Error
{
+ public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
+ {
+ parent::__construct($message, false, false, $previous);
+ }
}
} 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());
+ throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
}
}
} 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());
+ throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType(), $current->getLine()), $current->getValue()), $current->getLine(), $this->parser->getFilename());
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
switch ($name) {
case 'parent':
if (!count($this->parser->getBlockStack())) {
- throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line);
+ throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
}
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);
+ throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename());
}
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
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);
+ throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
}
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);
}
}
} else {
- throw new Twig_Error_Syntax('Expected name or number', $lineno);
+ throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
}
} else {
$type = Twig_TemplateInterface::ARRAY_CALL;
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());
+ throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
}
$targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
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)));
+ throw new LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this)));
}
return $this->attributes[$name];
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)));
+ throw new LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this)));
}
return $this->nodes[$name];
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
}
- throw new Twig_Error_Syntax($message, $this->getLine());
+ throw new Twig_Error_Syntax($message, $this->getLine(), $compiler->getFilename());
}
$this->compileFilter($compiler, $filter);
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
}
- throw new Twig_Error_Syntax($message, $this->getLine());
+ throw new Twig_Error_Syntax($message, $this->getLine(), $compiler->getFilename());
}
$compiler->raw($function->compile().'(');
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
}
- throw new Twig_Error_Syntax($message, $this->getLine());
+ throw new Twig_Error_Syntax($message, $this->getLine(), $compiler->getFilename());
}
$name = $this->getAttribute('name');
$this->changeIgnoreStrictCheck($node);
} else {
- throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine());
+ throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine(), $compiler->getFilename());
}
}
public function __construct(Twig_NodeInterface $body, $lineno, $tag = null)
{
parent::__construct(array('body' => $body), array(), $lineno, $tag);
-
- // in a sandbox tag, only include tags are allowed
- if (!$this->getNode('body') instanceof Twig_Node_Include) {
- foreach ($this->getNode('body') as $node) {
- if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
- continue;
- }
-
- if (!$node instanceof Twig_Node_Include) {
- throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section', $node->getLine());
- }
- }
- }
}
/**
return sprintf('__internal_%s', hash('sha1', uniqid(mt_rand(), true), false));
}
+ public function getFilename()
+ {
+ return $this->stream->getFilename();
+ }
+
/**
* Converts a token stream to a node tree.
*
}
}
} catch (Twig_Error_Syntax $e) {
- if (null === $e->getTemplateFile()) {
- $e->setTemplateFile($this->stream->getFilename());
+ if (!$e->getTemplateFile()) {
+ $e->setTemplateFile($this->getFilename());
+ }
+
+ if (!$e->getTemplateLine()) {
+ $e->setTemplateLine($this->stream->getCurrent()->getLine());
}
throw $e;
}
- $node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $this->stream->getFilename());
+ $node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $this->getFilename());
$traverser = new Twig_NodeTraverser($this->env, $this->visitors);
$token = $this->getCurrentToken();
if ($token->getType() !== Twig_Token::NAME_TYPE) {
- throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->stream->getFilename());
+ throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->getFilename());
}
if (null !== $test && call_user_func($test, $token)) {
$error .= sprintf(' (expecting closing tag for the "%s" tag defined near line %s)', $test[0]->getTag(), $lineno);
}
- throw new Twig_Error_Syntax($error, $token->getLine(), $this->stream->getFilename());
+ throw new Twig_Error_Syntax($error, $token->getLine(), $this->getFilename());
}
$message = sprintf('Unknown tag name "%s"', $token->getValue());
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
}
- throw new Twig_Error_Syntax($message, $token->getLine(), $this->stream->getFilename());
+ throw new Twig_Error_Syntax($message, $token->getLine(), $this->getFilename());
}
$this->stream->next();
break;
default:
- throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', -1, $this->stream->getFilename());
+ throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->getFilename());
}
}
}
if (in_array($name, $this->reservedMacroNames)) {
- throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword', $name), $node->getLine());
+ throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword', $name), $node->getLine(), $this->getFilename());
}
$this->macros[$name] = $node;
(!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface)
) {
if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) {
- throw new Twig_Error_Syntax('A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed.', $node->getLine(), $this->stream->getFilename());
+ throw new Twig_Error_Syntax('A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed.', $node->getLine(), $this->getFilename());
}
- throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->stream->getFilename());
+ throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->getFilename());
}
// bypass "set" nodes as they "capture" the output
try {
$this->doDisplay($context, $blocks);
} catch (Twig_Error $e) {
+ if (!$e->getTemplateFile()) {
+ $e->setTemplateFile($this->getTemplateName());
+ }
+
+ // this is mostly useful for Twig_Error_Loader exceptions
+ // see Twig_Error_Loader
+ if (false === $e->getTemplateLine()) {
+ $e->setTemplateLine(-1);
+ $e->guess();
+ }
+
throw $e;
} catch (Exception $e) {
throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, null, $e);
}
if (is_object($object)) {
- throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $item, get_class($object)));
+ throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
} elseif (is_array($object)) {
- throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $item, implode(', ', array_keys($object))));
+ throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $item, implode(', ', array_keys($object))), -1, $this->getTemplateName());
} else {
- throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a "%s" variable', $item, gettype($object)));
+ throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a "%s" variable', $item, gettype($object)), -1, $this->getTemplateName());
}
}
}
return null;
}
- throw new Twig_Error_Runtime(sprintf('Item "%s" for "%s" does not exist', $item, is_array($object) ? 'Array' : $object));
+ throw new Twig_Error_Runtime(sprintf('Item "%s" for "%s" does not exist', $item, is_array($object) ? 'Array' : $object), -1, $this->getTemplateName());
}
$class = get_class($object);
return null;
}
- throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)));
+ throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
}
if ($isDefinedTest) {
$name = 'INTERPOLATION_END_TYPE';
break;
default:
- throw new Twig_Error_Syntax(sprintf('Token of type "%s" does not exist.', $type), $line);
+ throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
}
return $short ? $name : 'Twig_Token::'.$name;
case self::INTERPOLATION_END_TYPE:
return 'end of string interpolation';
default:
- throw new Twig_Error_Syntax(sprintf('Token of type "%s" does not exist.', $type), $line);
+ throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
}
}
}
public function parse(Twig_Token $token)
{
$lineno = $token->getLine();
+ $stream = $this->parser->getStream();
- if ($this->parser->getStream()->test(Twig_Token::BLOCK_END_TYPE)) {
+ if ($stream->test(Twig_Token::BLOCK_END_TYPE)) {
$value = 'html';
} else {
$expr = $this->parser->getExpressionParser()->parseExpression();
if (!$expr instanceof Twig_Node_Expression_Constant) {
- throw new Twig_Error_Syntax('An escaping strategy must be a string or a Boolean.', $lineno);
+ throw new Twig_Error_Syntax('An escaping strategy must be a string or a Boolean.', $stream->getCurrent()->getLine(), $stream->getFilename());
}
$value = $expr->getAttribute('value');
$value = 'html';
}
- if ($compat && $this->parser->getStream()->test(Twig_Token::NAME_TYPE)) {
+ if ($compat && $stream->test(Twig_Token::NAME_TYPE)) {
if (false === $value) {
- throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $lineno);
+ throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getFilename());
}
- $value = $this->parser->getStream()->next()->getValue();
+ $value = $stream->next()->getValue();
}
}
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
return new Twig_Node_AutoEscape($value, $body, $lineno, $this->getTag());
}
$stream = $this->parser->getStream();
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
if ($this->parser->hasBlock($name)) {
- throw new Twig_Error_Syntax(sprintf("The block '$name' has already been defined line %d", $this->parser->getBlock($name)->getLine()), $lineno);
+ throw new Twig_Error_Syntax(sprintf("The block '$name' has already been defined line %d", $this->parser->getBlock($name)->getLine()), $stream->getCurrent()->getLine(), $stream->getFilename());
}
$this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno));
$this->parser->pushLocalScope();
$value = $stream->next()->getValue();
if ($value != $name) {
- throw new Twig_Error_Syntax(sprintf("Expected endblock for block '$name' (but %s given)", $value), $lineno);
+ throw new Twig_Error_Syntax(sprintf("Expected endblock for block '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
}
}
} else {
public function parse(Twig_Token $token)
{
if (!$this->parser->isMainScope()) {
- throw new Twig_Error_Syntax('Cannot extend from a block', $token->getLine());
+ throw new Twig_Error_Syntax('Cannot extend from a block', $token->getLine(), $this->parser->getFilename());
}
if (null !== $this->parser->getParent()) {
- throw new Twig_Error_Syntax('Multiple extends tags are forbidden', $token->getLine());
+ throw new Twig_Error_Syntax('Multiple extends tags are forbidden', $token->getLine(), $this->parser->getFilename());
}
$this->parser->setParent($this->parser->getExpressionParser()->parseExpression());
{
$lineno = $token->getLine();
$expr = $this->parser->getExpressionParser()->parseExpression();
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+ $stream = $this->parser->getStream();
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this, 'decideIfFork'));
$tests = array($expr, $body);
$else = null;
$end = false;
while (!$end) {
- switch ($this->parser->getStream()->next()->getValue()) {
+ switch ($stream->next()->getValue()) {
case 'else':
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
$else = $this->parser->subparse(array($this, 'decideIfEnd'));
break;
case 'elseif':
$expr = $this->parser->getExpressionParser()->parseExpression();
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this, 'decideIfFork'));
$tests[] = $expr;
$tests[] = $body;
break;
default:
- throw new Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d)', $lineno), -1);
+ throw new Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d)', $lineno), $stream->getCurrent()->getLine(), $stream->getFilename());
}
}
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
return new Twig_Node_If(new Twig_Node($tests), $else, $lineno, $this->getTag());
}
public function parse(Twig_Token $token)
{
$lineno = $token->getLine();
- $name = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue();
+ $stream = $this->parser->getStream();
+ $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
$arguments = $this->parser->getExpressionParser()->parseArguments();
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
$this->parser->pushLocalScope();
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
- if ($this->parser->getStream()->test(Twig_Token::NAME_TYPE)) {
- $value = $this->parser->getStream()->next()->getValue();
+ if ($stream->test(Twig_Token::NAME_TYPE)) {
+ $value = $stream->next()->getValue();
if ($value != $name) {
- throw new Twig_Error_Syntax(sprintf("Expected endmacro for macro '$name' (but %s given)", $value), $lineno);
+ throw new Twig_Error_Syntax(sprintf("Expected endmacro for macro '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
}
}
$this->parser->popLocalScope();
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
$this->parser->setMacro($name, new Twig_Node_Macro($name, new Twig_Node_Body(array($body)), $arguments, $lineno, $this->getTag()));
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+ // in a sandbox tag, only include tags are allowed
+ if (!$body instanceof Twig_Node_Include) {
+ foreach ($body as $node) {
+ if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
+ continue;
+ }
+
+ if (!$node instanceof Twig_Node_Include) {
+ throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section', $node->getLine(), $this->parser->getFilename());
+ }
+ }
+ }
+
return new Twig_Node_Sandbox($body, $token->getLine(), $this->getTag());
}
$stream->expect(Twig_Token::BLOCK_END_TYPE);
if (count($names) !== count($values)) {
- throw new Twig_Error_Syntax("When using set, you must have the same number of variables and assignements.", $lineno);
+ throw new Twig_Error_Syntax("When using set, you must have the same number of variables and assignements.", $stream->getCurrent()->getLine(), $stream->getFilename());
}
} else {
$capture = true;
if (count($names) > 1) {
- throw new Twig_Error_Syntax("When using set with a block, you cannot have a multi-target.", $lineno);
+ throw new Twig_Error_Syntax("When using set with a block, you cannot have a multi-target.", $stream->getCurrent()->getLine(), $stream->getFilename());
}
$stream->expect(Twig_Token::BLOCK_END_TYPE);
public function parse(Twig_Token $token)
{
$template = $this->parser->getExpressionParser()->parseExpression();
+ $stream = $this->parser->getStream();
if (!$template instanceof Twig_Node_Expression_Constant) {
- throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $token->getLine());
+ throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getFilename());
}
- $stream = $this->parser->getStream();
-
$targets = array();
if ($stream->test('with')) {
$stream->next();
{
foreach ($parsers as $parser) {
if (!$parser instanceof Twig_TokenParserInterface) {
- throw new Twig_Error('$parsers must a an array of Twig_TokenParserInterface');
+ throw new LogicException('$parsers must a an array of Twig_TokenParserInterface');
}
$this->parsers[$parser->getTag()] = $parser;
}
foreach ($brokers as $broker) {
if (!$broker instanceof Twig_TokenParserBrokerInterface) {
- throw new Twig_Error('$brokers must a an array of Twig_TokenParserBrokerInterface');
+ throw new LogicException('$brokers must a an array of Twig_TokenParserBrokerInterface');
}
$this->brokers[] = $broker;
}
public function next()
{
if (!isset($this->tokens[++$this->current])) {
- throw new Twig_Error_Syntax('Unexpected end of template', -1, $this->filename);
+ throw new Twig_Error_Syntax('Unexpected end of template', $this->token[$this->current - 1]->getLine(), $this->filename);
}
return $this->tokens[$this->current - 1];
public function look($number = 1)
{
if (!isset($this->tokens[$this->current + $number])) {
- throw new Twig_Error_Syntax('Unexpected end of template', -1, $this->filename);
+ throw new Twig_Error_Syntax('Unexpected end of template', $this->token[$this->current + $number - 1]->getLine(), $this->filename);
}
return $this->tokens[$this->current + $number];
--- /dev/null
+--TEST--
+"include" tag
+--TEMPLATE--
+{% include "foo.twig" %}
+--DATA--
+return array();
+--EXCEPTION--
+Twig_Error_Loader: Template "foo.twig" is not defined in "index.twig" at line 2.
--- /dev/null
+--TEST--
+"include" tag
+--TEMPLATE--
+{% extends "base.twig" %}
+
+{% block content %}
+ {{ parent() }}
+{% endblock %}
+--TEMPLATE(base.twig)--
+{% block content %}
+ {% include "foo.twig" %}
+{% endblock %}
+--DATA--
+return array();
+--EXCEPTION--
+Twig_Error_Loader: Template "foo.twig" is not defined in "base.twig" at line 3.
*/
public function testSetMacroThrowsExceptionOnReservedMethods()
{
- $parser = new Twig_Parser(new Twig_Environment());
+ $parser = $this->getParser();
$parser->setMacro('display', $this->getMock('Twig_Node_Macro', array(), array(), '', null));
}
*/
public function testFilterBodyNodes($input, $expected)
{
- $parser = $this->getParserForFilterBodyNodes();
+ $parser = $this->getParser();
$this->assertEquals($expected, $parser->filterBodyNodes($input));
}
*/
public function testFilterBodyNodesThrowsException($input)
{
- $parser = $this->getParserForFilterBodyNodes();
+ $parser = $this->getParser();
$parser->filterBodyNodes($input);
}
*/
public function testFilterBodyNodesWithBOM()
{
- $parser = $this->getParserForFilterBodyNodes();
+ $parser = $this->getParser();
$parser->filterBodyNodes(new Twig_Node_Text(chr(0xEF).chr(0xBB).chr(0xBF), 1));
}
));
}
- protected function getParserForFilterBodyNodes()
+ protected function getParser()
{
$parser = new TestParser(new Twig_Environment());
$parser->setParent(new Twig_Node());