Start working

Modified some paths to be more generic and not require rewrite.  Some
instances of phase names have been changed, others are still in process.
This commit is contained in:
mattbk
2015-10-28 22:04:20 -05:00
parent eda91ff492
commit abadd5bc38
192 changed files with 16085 additions and 7 deletions

399
Twig/Parser.php Normal file
View File

@ -0,0 +1,399 @@
<?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.
*/
/**
* Default parser implementation.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Parser implements Twig_ParserInterface
{
protected $stack = array();
protected $stream;
protected $parent;
protected $handlers;
protected $visitors;
protected $expressionParser;
protected $blocks;
protected $blockStack;
protected $macros;
protected $env;
protected $reservedMacroNames;
protected $importedSymbols;
protected $traits;
protected $embeddedTemplates = array();
/**
* Constructor.
*
* @param Twig_Environment $env A Twig_Environment instance
*/
public function __construct(Twig_Environment $env)
{
$this->env = $env;
}
public function getEnvironment()
{
return $this->env;
}
public function getVarName()
{
return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
}
public function getFilename()
{
return $this->stream->getFilename();
}
/**
* {@inheritdoc}
*/
public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false)
{
// push all variables into the stack to keep the current state of the parser
$vars = get_object_vars($this);
unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames']);
$this->stack[] = $vars;
// tag handlers
if (null === $this->handlers) {
$this->handlers = $this->env->getTokenParsers();
$this->handlers->setParser($this);
}
// node visitors
if (null === $this->visitors) {
$this->visitors = $this->env->getNodeVisitors();
}
if (null === $this->expressionParser) {
$this->expressionParser = new Twig_ExpressionParser($this, $this->env->getUnaryOperators(), $this->env->getBinaryOperators());
}
$this->stream = $stream;
$this->parent = null;
$this->blocks = array();
$this->macros = array();
$this->traits = array();
$this->blockStack = array();
$this->importedSymbols = array(array());
$this->embeddedTemplates = array();
try {
$body = $this->subparse($test, $dropNeedle);
if (null !== $this->parent) {
if (null === $body = $this->filterBodyNodes($body)) {
$body = new Twig_Node();
}
}
} catch (Twig_Error_Syntax $e) {
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->getFilename());
$traverser = new Twig_NodeTraverser($this->env, $this->visitors);
$node = $traverser->traverse($node);
// restore previous stack so previous parse() call can resume working
foreach (array_pop($this->stack) as $key => $val) {
$this->$key = $val;
}
return $node;
}
public function subparse($test, $dropNeedle = false)
{
$lineno = $this->getCurrentToken()->getLine();
$rv = array();
while (!$this->stream->isEOF()) {
switch ($this->getCurrentToken()->getType()) {
case Twig_Token::TEXT_TYPE:
$token = $this->stream->next();
$rv[] = new Twig_Node_Text($token->getValue(), $token->getLine());
break;
case Twig_Token::VAR_START_TYPE:
$token = $this->stream->next();
$expr = $this->expressionParser->parseExpression();
$this->stream->expect(Twig_Token::VAR_END_TYPE);
$rv[] = new Twig_Node_Print($expr, $token->getLine());
break;
case Twig_Token::BLOCK_START_TYPE:
$this->stream->next();
$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->getFilename());
}
if (null !== $test && call_user_func($test, $token)) {
if ($dropNeedle) {
$this->stream->next();
}
if (1 === count($rv)) {
return $rv[0];
}
return new Twig_Node($rv, array(), $lineno);
}
$subparser = $this->handlers->getTokenParser($token->getValue());
if (null === $subparser) {
if (null !== $test) {
$error = sprintf('Unexpected tag name "%s"', $token->getValue());
if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) {
$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->getFilename());
}
$message = sprintf('Unknown tag name "%s"', $token->getValue());
if ($alternatives = $this->env->computeAlternatives($token->getValue(), array_keys($this->env->getTags()))) {
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
}
throw new Twig_Error_Syntax($message, $token->getLine(), $this->getFilename());
}
$this->stream->next();
$node = $subparser->parse($token);
if (null !== $node) {
$rv[] = $node;
}
break;
default:
throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->getFilename());
}
}
if (1 === count($rv)) {
return $rv[0];
}
return new Twig_Node($rv, array(), $lineno);
}
public function addHandler($name, $class)
{
$this->handlers[$name] = $class;
}
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
{
$this->visitors[] = $visitor;
}
public function getBlockStack()
{
return $this->blockStack;
}
public function peekBlockStack()
{
return $this->blockStack[count($this->blockStack) - 1];
}
public function popBlockStack()
{
array_pop($this->blockStack);
}
public function pushBlockStack($name)
{
$this->blockStack[] = $name;
}
public function hasBlock($name)
{
return isset($this->blocks[$name]);
}
public function getBlock($name)
{
return $this->blocks[$name];
}
public function setBlock($name, Twig_Node_Block $value)
{
$this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getLine());
}
public function hasMacro($name)
{
return isset($this->macros[$name]);
}
public function setMacro($name, Twig_Node_Macro $node)
{
if ($this->isReservedMacroName($name)) {
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;
}
public function isReservedMacroName($name)
{
if (null === $this->reservedMacroNames) {
$this->reservedMacroNames = array();
$r = new ReflectionClass($this->env->getBaseTemplateClass());
foreach ($r->getMethods() as $method) {
$methodName = strtolower($method->getName());
if ('get' === substr($methodName, 0, 3) && isset($methodName[3])) {
$this->reservedMacroNames[] = substr($methodName, 3);
}
}
}
return in_array(strtolower($name), $this->reservedMacroNames);
}
public function addTrait($trait)
{
$this->traits[] = $trait;
}
public function hasTraits()
{
return count($this->traits) > 0;
}
public function embedTemplate(Twig_Node_Module $template)
{
$template->setIndex(mt_rand());
$this->embeddedTemplates[] = $template;
}
public function addImportedSymbol($type, $alias, $name = null, Twig_Node_Expression $node = null)
{
$this->importedSymbols[0][$type][$alias] = array('name' => $name, 'node' => $node);
}
public function getImportedSymbol($type, $alias)
{
foreach ($this->importedSymbols as $functions) {
if (isset($functions[$type][$alias])) {
return $functions[$type][$alias];
}
}
}
public function isMainScope()
{
return 1 === count($this->importedSymbols);
}
public function pushLocalScope()
{
array_unshift($this->importedSymbols, array());
}
public function popLocalScope()
{
array_shift($this->importedSymbols);
}
/**
* Gets the expression parser.
*
* @return Twig_ExpressionParser The expression parser
*/
public function getExpressionParser()
{
return $this->expressionParser;
}
public function getParent()
{
return $this->parent;
}
public function setParent($parent)
{
$this->parent = $parent;
}
/**
* Gets the token stream.
*
* @return Twig_TokenStream The token stream
*/
public function getStream()
{
return $this->stream;
}
/**
* Gets the current token.
*
* @return Twig_Token The current token
*/
public function getCurrentToken()
{
return $this->stream->getCurrent();
}
protected function filterBodyNodes(Twig_NodeInterface $node)
{
// check that the body does not contain non-empty output nodes
if (
($node instanceof Twig_Node_Text && !ctype_space($node->getAttribute('data')))
||
(!$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->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
if ($node instanceof Twig_Node_Set) {
return $node;
}
if ($node instanceof Twig_NodeOutputInterface) {
return;
}
foreach ($node as $k => $n) {
if (null !== $n && null === $this->filterBodyNodes($n)) {
$node->removeNode($k);
}
}
return $node;
}
}