You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ih...@apache.org on 2012/05/22 16:42:31 UTC

svn commit: r1341499 [6/7] - in /logging/site/branches/experimental-twig-textile: ./ libs/Twig/ libs/Twig/lib/ libs/Twig/lib/Twig/ libs/Twig/lib/Twig/Error/ libs/Twig/lib/Twig/Extension/ libs/Twig/lib/Twig/Filter/ libs/Twig/lib/Twig/Function/ libs/Twig...

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Parser.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Parser.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Parser.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Parser.php Tue May 22 14:42:25 2012
@@ -0,0 +1,384 @@
+<?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.
+ *
+ * @package twig
+ * @author  Fabien Potencier <fa...@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 $importedFunctions;
+    protected $tmpVarCount;
+    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_%d', substr($this->env->getTemplateClass($this->stream->getFilename()), strlen($this->env->getTemplateClassPrefix())), ++$this->tmpVarCount);
+    }
+
+    /**
+     * Converts a token stream to a node tree.
+     *
+     * @param  Twig_TokenStream $stream A token stream instance
+     *
+     * @return Twig_Node_Module A node tree
+     */
+    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']);
+        $this->stack[] = $vars;
+
+        $this->tmpVarCount = 0;
+
+        // 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->importedFunctions = 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 (null === $e->getTemplateFile()) {
+                $e->setTemplateFile($this->stream->getFilename());
+            }
+
+            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());
+
+        $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->stream->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) {
+                            throw new Twig_Error_Syntax(sprintf('Unexpected tag name "%s" (expecting closing tag for the "%s" tag defined near line %s)', $token->getValue(), $test[0]->getTag(), $lineno), $token->getLine(), $this->stream->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->stream->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.', -1, $this->stream->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, $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 (null === $this->reservedMacroNames) {
+            $this->reservedMacroNames = array();
+            $r = new ReflectionClass($this->env->getBaseTemplateClass());
+            foreach ($r->getMethods() as $method) {
+                $this->reservedMacroNames[] = $method->getName();
+            }
+        }
+
+        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());
+        }
+
+        $this->macros[$name] = $node;
+    }
+
+    public function addTrait($trait)
+    {
+        $this->traits[] = $trait;
+    }
+
+    public function hasTraits()
+    {
+        return count($this->traits) > 0;
+    }
+
+    public function embedTemplate(Twig_Node_Module $template)
+    {
+        $template->setIndex(count($this->embeddedTemplates) + 1);
+
+        $this->embeddedTemplates[] = $template;
+    }
+
+    public function addImportedFunction($alias, $name, Twig_Node_Expression $node)
+    {
+        $this->importedFunctions[0][$alias] = array('name' => $name, 'node' => $node);
+    }
+
+    public function getImportedFunction($alias)
+    {
+        foreach ($this->importedFunctions as $functions) {
+            if (isset($functions[$alias])) {
+                return $functions[$alias];
+            }
+        }
+    }
+
+    public function isMainScope()
+    {
+        return 1 === count($this->importedFunctions);
+    }
+
+    public function pushLocalScope()
+    {
+        array_unshift($this->importedFunctions, array());
+    }
+
+    public function popLocalScope()
+    {
+        array_shift($this->importedFunctions);
+    }
+
+    /**
+     * 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->stream->getFilename());
+            }
+
+            throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->stream->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 === $n = $this->filterBodyNodes($n)) {
+                $node->removeNode($k);
+            }
+        }
+
+        return $node;
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/ParserInterface.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/ParserInterface.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/ParserInterface.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/ParserInterface.php Tue May 22 14:42:25 2012
@@ -0,0 +1,28 @@
+<?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 parser classes.
+ *
+ * @package twig
+ * @author  Fabien Potencier <fa...@symfony.com>
+ */
+interface Twig_ParserInterface
+{
+    /**
+     * Converts a token stream to a node tree.
+     *
+     * @param  Twig_TokenStream $stream A token stream instance
+     *
+     * @return Twig_Node_Module A node tree
+     */
+    function parse(Twig_TokenStream $stream);
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Sandbox/SecurityError.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Sandbox/SecurityError.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Sandbox/SecurityError.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Sandbox/SecurityError.php Tue May 22 14:42:25 2012
@@ -0,0 +1,20 @@
+<?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.
+ */
+
+/**
+ * Exception thrown when a security error occurs at runtime.
+ *
+ * @package    twig
+ * @author     Fabien Potencier <fa...@symfony.com>
+ */
+class Twig_Sandbox_SecurityError extends Twig_Error
+{
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Sandbox/SecurityPolicy.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Sandbox/SecurityPolicy.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Sandbox/SecurityPolicy.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Sandbox/SecurityPolicy.php Tue May 22 14:42:25 2012
@@ -0,0 +1,120 @@
+<?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 security policy which need to be enforced when sandbox mode is enabled.
+ *
+ * @package    twig
+ * @author     Fabien Potencier <fa...@symfony.com>
+ */
+class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterface
+{
+    protected $allowedTags;
+    protected $allowedFilters;
+    protected $allowedMethods;
+    protected $allowedProperties;
+    protected $allowedFunctions;
+
+    public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array(), array $allowedProperties = array(), array $allowedFunctions = array())
+    {
+        $this->allowedTags = $allowedTags;
+        $this->allowedFilters = $allowedFilters;
+        $this->setAllowedMethods($allowedMethods);
+        $this->allowedProperties = $allowedProperties;
+        $this->allowedFunctions = $allowedFunctions;
+    }
+
+    public function setAllowedTags(array $tags)
+    {
+        $this->allowedTags = $tags;
+    }
+
+    public function setAllowedFilters(array $filters)
+    {
+        $this->allowedFilters = $filters;
+    }
+
+    public function setAllowedMethods(array $methods)
+    {
+        $this->allowedMethods = array();
+        foreach ($methods as $class => $m) {
+            $this->allowedMethods[$class] = array_map('strtolower', is_array($m) ? $m : array($m));
+        }
+    }
+
+    public function setAllowedProperties(array $properties)
+    {
+        $this->allowedProperties = $properties;
+    }
+
+    public function setAllowedFunctions(array $functions)
+    {
+        $this->allowedFunctions = $functions;
+    }
+
+    public function checkSecurity($tags, $filters, $functions)
+    {
+        foreach ($tags as $tag) {
+            if (!in_array($tag, $this->allowedTags)) {
+                throw new Twig_Sandbox_SecurityError(sprintf('Tag "%s" is not allowed.', $tag));
+            }
+        }
+
+        foreach ($filters as $filter) {
+            if (!in_array($filter, $this->allowedFilters)) {
+                throw new Twig_Sandbox_SecurityError(sprintf('Filter "%s" is not allowed.', $filter));
+            }
+        }
+
+        foreach ($functions as $function) {
+            if (!in_array($function, $this->allowedFunctions)) {
+                throw new Twig_Sandbox_SecurityError(sprintf('Function "%s" is not allowed.', $function));
+            }
+        }
+    }
+
+    public function checkMethodAllowed($obj, $method)
+    {
+        if ($obj instanceof Twig_TemplateInterface || $obj instanceof Twig_Markup) {
+            return true;
+        }
+
+        $allowed = false;
+        $method = strtolower($method);
+        foreach ($this->allowedMethods as $class => $methods) {
+            if ($obj instanceof $class) {
+                $allowed = in_array($method, $methods);
+
+                break;
+            }
+        }
+
+        if (!$allowed) {
+            throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj)));
+        }
+    }
+
+    public function checkPropertyAllowed($obj, $property)
+    {
+        $allowed = false;
+        foreach ($this->allowedProperties as $class => $properties) {
+            if ($obj instanceof $class) {
+                $allowed = in_array($property, is_array($properties) ? $properties : array($properties));
+
+                break;
+            }
+        }
+
+        if (!$allowed) {
+            throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, get_class($obj)));
+        }
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Sandbox/SecurityPolicyInterface.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Sandbox/SecurityPolicyInterface.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Sandbox/SecurityPolicyInterface.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Sandbox/SecurityPolicyInterface.php Tue May 22 14:42:25 2012
@@ -0,0 +1,25 @@
+<?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.
+ */
+
+/**
+ * Interfaces that all security policy classes must implements.
+ *
+ * @package    twig
+ * @author     Fabien Potencier <fa...@symfony.com>
+ */
+interface Twig_Sandbox_SecurityPolicyInterface
+{
+    function checkSecurity($tags, $filters, $functions);
+
+    function checkMethodAllowed($obj, $method);
+
+    function checkPropertyAllowed($obj, $method);
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Template.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Template.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Template.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Template.php Tue May 22 14:42:25 2012
@@ -0,0 +1,442 @@
+<?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 base class for compiled templates.
+ *
+ * @package twig
+ * @author  Fabien Potencier <fa...@symfony.com>
+ */
+abstract class Twig_Template implements Twig_TemplateInterface
+{
+    static protected $cache = array();
+
+    protected $parent;
+    protected $parents;
+    protected $env;
+    protected $blocks;
+    protected $traits;
+
+    /**
+     * Constructor.
+     *
+     * @param Twig_Environment $env A Twig_Environment instance
+     */
+    public function __construct(Twig_Environment $env)
+    {
+        $this->env = $env;
+        $this->blocks = array();
+        $this->traits = array();
+    }
+
+    /**
+     * Returns the template name.
+     *
+     * @return string The template name
+     */
+    abstract public function getTemplateName();
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getEnvironment()
+    {
+        return $this->env;
+    }
+
+    /**
+     * Returns the parent template.
+     *
+     * This method is for internal use only and should never be called
+     * directly.
+     *
+     * @return Twig_TemplateInterface|false The parent template or false if there is no parent
+     */
+    public function getParent(array $context)
+    {
+        if (null !== $this->parent) {
+            return $this->parent;
+        }
+
+        $parent = $this->doGetParent($context);
+        if (false === $parent) {
+            return false;
+        } elseif ($parent instanceof Twig_Template) {
+            $name = $parent->getTemplateName();
+            $this->parents[$name] = $parent;
+            $parent = $name;
+        } elseif (!isset($this->parents[$parent])) {
+            $this->parents[$parent] = $this->env->loadTemplate($parent);
+        }
+
+        return $this->parents[$parent];
+    }
+
+    protected function doGetParent(array $context)
+    {
+        return false;
+    }
+
+    public function isTraitable()
+    {
+        return true;
+    }
+
+    /**
+     * Displays a parent block.
+     *
+     * This method is for internal use only and should never be called
+     * directly.
+     *
+     * @param string $name    The block name to display from the parent
+     * @param array  $context The context
+     * @param array  $blocks  The current set of blocks
+     */
+    public function displayParentBlock($name, array $context, array $blocks = array())
+    {
+        $name = (string) $name;
+
+        if (isset($this->traits[$name])) {
+            $this->traits[$name][0]->displayBlock($name, $context, $blocks);
+        } elseif (false !== $parent = $this->getParent($context)) {
+            $parent->displayBlock($name, $context, $blocks);
+        } else {
+            throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName());
+        }
+    }
+
+    /**
+     * Displays a block.
+     *
+     * This method is for internal use only and should never be called
+     * directly.
+     *
+     * @param string $name    The block name to display
+     * @param array  $context The context
+     * @param array  $blocks  The current set of blocks
+     */
+    public function displayBlock($name, array $context, array $blocks = array())
+    {
+        $name = (string) $name;
+
+        if (isset($blocks[$name])) {
+            $b = $blocks;
+            unset($b[$name]);
+            call_user_func($blocks[$name], $context, $b);
+        } elseif (isset($this->blocks[$name])) {
+            call_user_func($this->blocks[$name], $context, $blocks);
+        } elseif (false !== $parent = $this->getParent($context)) {
+            $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks));
+        }
+    }
+
+    /**
+     * Renders a parent block.
+     *
+     * This method is for internal use only and should never be called
+     * directly.
+     *
+     * @param string $name    The block name to render from the parent
+     * @param array  $context The context
+     * @param array  $blocks  The current set of blocks
+     *
+     * @return string The rendered block
+     */
+    public function renderParentBlock($name, array $context, array $blocks = array())
+    {
+        ob_start();
+        $this->displayParentBlock($name, $context, $blocks);
+
+        return ob_get_clean();
+    }
+
+    /**
+     * Renders a block.
+     *
+     * This method is for internal use only and should never be called
+     * directly.
+     *
+     * @param string $name    The block name to render
+     * @param array  $context The context
+     * @param array  $blocks  The current set of blocks
+     *
+     * @return string The rendered block
+     */
+    public function renderBlock($name, array $context, array $blocks = array())
+    {
+        ob_start();
+        $this->displayBlock($name, $context, $blocks);
+
+        return ob_get_clean();
+    }
+
+    /**
+     * Returns whether a block exists or not.
+     *
+     * This method is for internal use only and should never be called
+     * directly.
+     *
+     * This method does only return blocks defined in the current template
+     * or defined in "used" traits.
+     *
+     * It does not return blocks from parent templates as the parent
+     * template name can be dynamic, which is only known based on the
+     * current context.
+     *
+     * @param string $name The block name
+     *
+     * @return Boolean true if the block exists, false otherwise
+     */
+    public function hasBlock($name)
+    {
+        return isset($this->blocks[(string) $name]);
+    }
+
+    /**
+     * Returns all block names.
+     *
+     * This method is for internal use only and should never be called
+     * directly.
+     *
+     * @return array An array of block names
+     *
+     * @see hasBlock
+     */
+    public function getBlockNames()
+    {
+        return array_keys($this->blocks);
+    }
+
+    /**
+     * Returns all blocks.
+     *
+     * This method is for internal use only and should never be called
+     * directly.
+     *
+     * @return array An array of blocks
+     *
+     * @see hasBlock
+     */
+    public function getBlocks()
+    {
+        return $this->blocks;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function display(array $context, array $blocks = array())
+    {
+        $this->displayWithErrorHandling($this->env->mergeGlobals($context), $blocks);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function render(array $context)
+    {
+        $level = ob_get_level();
+        ob_start();
+        try {
+            $this->display($context);
+        } catch (Exception $e) {
+            while (ob_get_level() > $level) {
+                ob_end_clean();
+            }
+
+            throw $e;
+        }
+
+        return ob_get_clean();
+    }
+
+    protected function displayWithErrorHandling(array $context, array $blocks = array())
+    {
+        try {
+            $this->doDisplay($context, $blocks);
+        } catch (Twig_Error $e) {
+            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);
+        }
+    }
+
+    /**
+     * Auto-generated method to display the template with the given context.
+     *
+     * @param array $context An array of parameters to pass to the template
+     * @param array $blocks  An array of blocks to pass to the template
+     */
+    abstract protected function doDisplay(array $context, array $blocks = array());
+
+    /**
+     * Returns a variable from the context.
+     *
+     * This method is for internal use only and should never be called
+     * directly.
+     *
+     * This method should not be overriden in a sub-class as this is an
+     * implementation detail that has been introduced to optimize variable
+     * access for versions of PHP before 5.4. This is not a way to override
+     * the way to get a variable value.
+     *
+     * @param array   $context           The context
+     * @param string  $item              The variable to return from the context
+     * @param Boolean $ignoreStrictCheck Whether to ignore the strict variable check or not
+     *
+     * @return The content of the context variable
+     *
+     * @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode
+     */
+    final protected function getContext($context, $item, $ignoreStrictCheck = false)
+    {
+        if (!array_key_exists($item, $context)) {
+            if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
+                return null;
+            }
+
+            throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item));
+        }
+
+        return $context[$item];
+    }
+
+    /**
+     * Returns the attribute value for a given array/object.
+     *
+     * @param mixed   $object            The object or array from where to get the item
+     * @param mixed   $item              The item to get from the array or object
+     * @param array   $arguments         An array of arguments to pass if the item is an object method
+     * @param string  $type              The type of attribute (@see Twig_TemplateInterface)
+     * @param Boolean $isDefinedTest     Whether this is only a defined check
+     * @param Boolean $ignoreStrictCheck Whether to ignore the strict attribute check or not
+     *
+     * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true
+     *
+     * @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false
+     */
+    protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
+    {
+        $item = is_numeric($item) ? (int) $item : (string) $item;
+
+        // array
+        if (Twig_TemplateInterface::METHOD_CALL !== $type) {
+            if ((is_array($object) && array_key_exists($item, $object))
+                || ($object instanceof ArrayAccess && isset($object[$item]))
+            ) {
+                if ($isDefinedTest) {
+                    return true;
+                }
+
+                return $object[$item];
+            }
+
+            if (Twig_TemplateInterface::ARRAY_CALL === $type) {
+                if ($isDefinedTest) {
+                    return false;
+                }
+
+                if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
+                    return null;
+                }
+
+                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)));
+                } 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))));
+                } else {
+                    throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a "%s" variable', $item, gettype($object)));
+                }
+            }
+        }
+
+        if (!is_object($object)) {
+            if ($isDefinedTest) {
+                return false;
+            }
+
+            if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
+                return null;
+            }
+
+            throw new Twig_Error_Runtime(sprintf('Item "%s" for "%s" does not exist', $item, is_array($object) ? 'Array' : $object));
+        }
+
+        $class = get_class($object);
+
+        // object property
+        if (Twig_TemplateInterface::METHOD_CALL !== $type) {
+            if (isset($object->$item) || array_key_exists($item, $object)) {
+                if ($isDefinedTest) {
+                    return true;
+                }
+
+                if ($this->env->hasExtension('sandbox')) {
+                    $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
+                }
+
+                return $object->$item;
+            }
+        }
+
+        // object method
+        if (!isset(self::$cache[$class]['methods'])) {
+            self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
+        }
+
+        $lcItem = strtolower($item);
+        if (isset(self::$cache[$class]['methods'][$lcItem])) {
+            $method = $item;
+        } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
+            $method = 'get'.$item;
+        } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
+            $method = 'is'.$item;
+        } elseif (isset(self::$cache[$class]['methods']['__call'])) {
+            $method = $item;
+        } else {
+            if ($isDefinedTest) {
+                return false;
+            }
+
+            if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
+                return null;
+            }
+
+            throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)));
+        }
+
+        if ($isDefinedTest) {
+            return true;
+        }
+
+        if ($this->env->hasExtension('sandbox')) {
+            $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
+        }
+
+        $ret = call_user_func_array(array($object, $method), $arguments);
+
+        // hack to be removed when macro calls are refactored
+        if ($object instanceof Twig_TemplateInterface) {
+            return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
+        }
+
+        return $ret;
+    }
+
+    /**
+     * This method is only useful when testing Twig. Do not use it.
+     */
+    static public function clearCache()
+    {
+        self::$cache = array();
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TemplateInterface.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TemplateInterface.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TemplateInterface.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TemplateInterface.php Tue May 22 14:42:25 2012
@@ -0,0 +1,47 @@
+<?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 all compiled templates.
+ *
+ * @package twig
+ * @author  Fabien Potencier <fa...@symfony.com>
+ */
+interface Twig_TemplateInterface
+{
+    const ANY_CALL    = 'any';
+    const ARRAY_CALL  = 'array';
+    const METHOD_CALL = 'method';
+
+    /**
+     * Renders the template with the given context and returns it as string.
+     *
+     * @param array $context An array of parameters to pass to the template
+     *
+     * @return string The rendered template
+     */
+    function render(array $context);
+
+    /**
+     * Displays the template with the given context.
+     *
+     * @param array $context An array of parameters to pass to the template
+     * @param array $blocks  An array of blocks to pass to the template
+     */
+    function display(array $context, array $blocks = array());
+
+    /**
+     * Returns the bound environment for this template.
+     *
+     * @return Twig_Environment The current environment
+     */
+    function getEnvironment();
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Test/Function.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Test/Function.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Test/Function.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Test/Function.php Tue May 22 14:42:25 2012
@@ -0,0 +1,31 @@
+<?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 function template test.
+ *
+ * @package    twig
+ * @author     Fabien Potencier <fa...@symfony.com>
+ */
+class Twig_Test_Function implements Twig_TestInterface
+{
+    protected $function;
+
+    public function __construct($function)
+    {
+        $this->function = $function;
+    }
+
+    public function compile()
+    {
+        return $this->function;
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Test/Method.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Test/Method.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Test/Method.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Test/Method.php Tue May 22 14:42:25 2012
@@ -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.
+ */
+
+/**
+ * Represents a method template test.
+ *
+ * @package    twig
+ * @author     Fabien Potencier <fa...@symfony.com>
+ */
+class Twig_Test_Method implements Twig_TestInterface
+{
+    protected $extension;
+    protected $method;
+
+    public function __construct(Twig_ExtensionInterface $extension, $method)
+    {
+        $this->extension = $extension;
+        $this->method = $method;
+    }
+
+    public function compile()
+    {
+        return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Test/Node.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Test/Node.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Test/Node.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Test/Node.php Tue May 22 14:42:25 2012
@@ -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.
+ */
+
+/**
+ * Represents a template test as a Node.
+ *
+ * @package    twig
+ * @author     Fabien Potencier <fa...@symfony.com>
+ */
+class Twig_Test_Node implements Twig_TestInterface
+{
+    protected $class;
+
+    public function __construct($class)
+    {
+        $this->class = $class;
+    }
+
+    public function getClass()
+    {
+        return $this->class;
+    }
+
+    public function compile()
+    {
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TestInterface.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TestInterface.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TestInterface.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TestInterface.php Tue May 22 14:42:25 2012
@@ -0,0 +1,26 @@
+<?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 test.
+ *
+ * @package    twig
+ * @author     Fabien Potencier <fa...@symfony.com>
+ */
+interface Twig_TestInterface
+{
+    /**
+     * Compiles a test.
+     *
+     * @return string The PHP code for the test
+     */
+    function compile();
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Token.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Token.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Token.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/Token.php Tue May 22 14:42:25 2012
@@ -0,0 +1,219 @@
+<?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 Token.
+ *
+ * @package twig
+ * @author  Fabien Potencier <fa...@symfony.com>
+ */
+class Twig_Token
+{
+    protected $value;
+    protected $type;
+    protected $lineno;
+
+    const EOF_TYPE                  = -1;
+    const TEXT_TYPE                 = 0;
+    const BLOCK_START_TYPE          = 1;
+    const VAR_START_TYPE            = 2;
+    const BLOCK_END_TYPE            = 3;
+    const VAR_END_TYPE              = 4;
+    const NAME_TYPE                 = 5;
+    const NUMBER_TYPE               = 6;
+    const STRING_TYPE               = 7;
+    const OPERATOR_TYPE             = 8;
+    const PUNCTUATION_TYPE          = 9;
+    const INTERPOLATION_START_TYPE  = 10;
+    const INTERPOLATION_END_TYPE    = 11;
+
+    /**
+     * Constructor.
+     *
+     * @param integer $type   The type of the token
+     * @param string  $value  The token value
+     * @param integer $lineno The line position in the source
+     */
+    public function __construct($type, $value, $lineno)
+    {
+        $this->type   = $type;
+        $this->value  = $value;
+        $this->lineno = $lineno;
+    }
+
+    /**
+     * Returns a string representation of the token.
+     *
+     * @return string A string representation of the token
+     */
+    public function __toString()
+    {
+        return sprintf('%s(%s)', self::typeToString($this->type, true, $this->lineno), $this->value);
+    }
+
+    /**
+     * Tests the current token for a type and/or a value.
+     *
+     * Parameters may be:
+     * * just type
+     * * type and value (or array of possible values)
+     * * just value (or array of possible values) (NAME_TYPE is used as type)
+     *
+     * @param array|integer     $type   The type to test
+     * @param array|string|null $values The token value
+     *
+     * @return Boolean
+     */
+    public function test($type, $values = null)
+    {
+        if (null === $values && !is_int($type)) {
+            $values = $type;
+            $type = self::NAME_TYPE;
+        }
+
+        return ($this->type === $type) && (
+            null === $values ||
+            (is_array($values) && in_array($this->value, $values)) ||
+            $this->value == $values
+        );
+    }
+
+    /**
+     * Gets the line.
+     *
+     * @return integer The source line
+     */
+    public function getLine()
+    {
+        return $this->lineno;
+    }
+
+    /**
+     * Gets the token type.
+     *
+     * @return integer The token type
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * Gets the token value.
+     *
+     * @return string The token value
+     */
+    public function getValue()
+    {
+        return $this->value;
+    }
+
+    /**
+     * Returns the constant representation (internal) of a given type.
+     *
+     * @param integer $type  The type as an integer
+     * @param Boolean $short Whether to return a short representation or not
+     * @param integer $line  The code line
+     *
+     * @return string The string representation
+     */
+    static public function typeToString($type, $short = false, $line = -1)
+    {
+        switch ($type) {
+            case self::EOF_TYPE:
+                $name = 'EOF_TYPE';
+                break;
+            case self::TEXT_TYPE:
+                $name = 'TEXT_TYPE';
+                break;
+            case self::BLOCK_START_TYPE:
+                $name = 'BLOCK_START_TYPE';
+                break;
+            case self::VAR_START_TYPE:
+                $name = 'VAR_START_TYPE';
+                break;
+            case self::BLOCK_END_TYPE:
+                $name = 'BLOCK_END_TYPE';
+                break;
+            case self::VAR_END_TYPE:
+                $name = 'VAR_END_TYPE';
+                break;
+            case self::NAME_TYPE:
+                $name = 'NAME_TYPE';
+                break;
+            case self::NUMBER_TYPE:
+                $name = 'NUMBER_TYPE';
+                break;
+            case self::STRING_TYPE:
+                $name = 'STRING_TYPE';
+                break;
+            case self::OPERATOR_TYPE:
+                $name = 'OPERATOR_TYPE';
+                break;
+            case self::PUNCTUATION_TYPE:
+                $name = 'PUNCTUATION_TYPE';
+                break;
+            case self::INTERPOLATION_START_TYPE:
+                $name = 'INTERPOLATION_START_TYPE';
+                break;
+            case self::INTERPOLATION_END_TYPE:
+                $name = 'INTERPOLATION_END_TYPE';
+                break;
+            default:
+                throw new Twig_Error_Syntax(sprintf('Token of type "%s" does not exist.', $type), $line);
+        }
+
+        return $short ? $name : 'Twig_Token::'.$name;
+    }
+
+    /**
+     * Returns the english representation of a given type.
+     *
+     * @param integer $type The type as an integer
+     * @param integer $line The code line
+     *
+     * @return string The string representation
+     */
+    static public function typeToEnglish($type, $line = -1)
+    {
+        switch ($type) {
+            case self::EOF_TYPE:
+                return 'end of template';
+            case self::TEXT_TYPE:
+                return 'text';
+            case self::BLOCK_START_TYPE:
+                return 'begin of statement block';
+            case self::VAR_START_TYPE:
+                return 'begin of print statement';
+            case self::BLOCK_END_TYPE:
+                return 'end of statement block';
+            case self::VAR_END_TYPE:
+                return 'end of print statement';
+            case self::NAME_TYPE:
+                return 'name';
+            case self::NUMBER_TYPE:
+                return 'number';
+            case self::STRING_TYPE:
+                return 'string';
+            case self::OPERATOR_TYPE:
+                return 'operator';
+            case self::PUNCTUATION_TYPE:
+                return 'punctuation';
+            case self::INTERPOLATION_START_TYPE:
+                return 'begin of string interpolation';
+            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);
+        }
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser.php Tue May 22 14:42:25 2012
@@ -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.
+ */
+
+/**
+ * Base class for all token parsers.
+ *
+ * @package twig
+ * @author  Fabien Potencier <fa...@symfony.com>
+ */
+abstract class Twig_TokenParser implements Twig_TokenParserInterface
+{
+    /**
+     * @var Twig_Parser
+     */
+    protected $parser;
+
+    /**
+     * Sets the parser associated with this token parser
+     *
+     * @param $parser A Twig_Parser instance
+     */
+    public function setParser(Twig_Parser $parser)
+    {
+        $this->parser = $parser;
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/AutoEscape.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/AutoEscape.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/AutoEscape.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/AutoEscape.php Tue May 22 14:42:25 2012
@@ -0,0 +1,88 @@
+<?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.
+ */
+
+/**
+ * Marks a section of a template to be escaped or not.
+ *
+ * <pre>
+ * {% autoescape true %}
+ *   Everything will be automatically escaped in this block
+ * {% endautoescape %}
+ *
+ * {% autoescape false %}
+ *   Everything will be outputed as is in this block
+ * {% endautoescape %}
+ *
+ * {% autoescape true js %}
+ *   Everything will be automatically escaped in this block
+ *   using the js escaping strategy
+ * {% endautoescape %}
+ * </pre>
+ */
+class Twig_TokenParser_AutoEscape extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $lineno = $token->getLine();
+
+        if ($this->parser->getStream()->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);
+            }
+            $value = $expr->getAttribute('value');
+
+            $compat = true === $value || false === $value;
+
+            if (true === $value) {
+                $value = 'html';
+            }
+
+            if ($compat && $this->parser->getStream()->test(Twig_Token::NAME_TYPE)) {
+                if (false === $value) {
+                    throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $lineno);
+                }
+
+                $value = $this->parser->getStream()->next()->getValue();
+            }
+        }
+
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+        $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+
+        return new Twig_Node_AutoEscape($value, $body, $lineno, $this->getTag());
+    }
+
+    public function decideBlockEnd(Twig_Token $token)
+    {
+        return $token->test('endautoescape');
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'autoescape';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Block.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Block.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Block.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Block.php Tue May 22 14:42:25 2012
@@ -0,0 +1,83 @@
+<?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.
+ */
+
+/**
+ * Marks a section of a template as being reusable.
+ *
+ * <pre>
+ *  {% block head %}
+ *    <link rel="stylesheet" href="style.css" />
+ *    <title>{% block title %}{% endblock %} - My Webpage</title>
+ *  {% endblock %}
+ * </pre>
+ */
+class Twig_TokenParser_Block extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $lineno = $token->getLine();
+        $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);
+        }
+        $this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno));
+        $this->parser->pushLocalScope();
+        $this->parser->pushBlockStack($name);
+
+        if ($stream->test(Twig_Token::BLOCK_END_TYPE)) {
+            $stream->next();
+
+            $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
+            if ($stream->test(Twig_Token::NAME_TYPE)) {
+                $value = $stream->next()->getValue();
+
+                if ($value != $name) {
+                    throw new Twig_Error_Syntax(sprintf("Expected endblock for block '$name' (but %s given)", $value), $lineno);
+                }
+            }
+        } else {
+            $body = new Twig_Node(array(
+                new Twig_Node_Print($this->parser->getExpressionParser()->parseExpression(), $lineno),
+            ));
+        }
+        $stream->expect(Twig_Token::BLOCK_END_TYPE);
+
+        $block->setNode('body', $body);
+        $this->parser->popBlockStack();
+        $this->parser->popLocalScope();
+
+        return new Twig_Node_BlockReference($name, $lineno, $this->getTag());
+    }
+
+    public function decideBlockEnd(Twig_Token $token)
+    {
+        return $token->test('endblock');
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'block';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Do.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Do.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Do.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Do.php Tue May 22 14:42:25 2012
@@ -0,0 +1,42 @@
+<?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.
+ */
+
+/**
+ * Evaluates an expression, disgarding the returned value.
+ */
+class Twig_TokenParser_Do extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $expr = $this->parser->getExpressionParser()->parseExpression();
+
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+
+        return new Twig_Node_Do($expr, $token->getLine(), $this->getTag());
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'do';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Embed.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Embed.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Embed.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Embed.php Tue May 22 14:42:25 2012
@@ -0,0 +1,66 @@
+<?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.
+ */
+
+/**
+ * Embeds a template.
+ */
+class Twig_TokenParser_Embed extends Twig_TokenParser_Include
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $stream = $this->parser->getStream();
+
+        $parent = $this->parser->getExpressionParser()->parseExpression();
+
+        list($variables, $only, $ignoreMissing) = $this->parseArguments();
+
+        // inject a fake parent to make the parent() function work
+        $stream->injectTokens(array(
+            new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', $token->getLine()),
+            new Twig_Token(Twig_Token::NAME_TYPE, 'extends', $token->getLine()),
+            new Twig_Token(Twig_Token::STRING_TYPE, '__parent__', $token->getLine()),
+            new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', $token->getLine()),
+        ));
+
+        $module = $this->parser->parse($stream, array($this, 'decideBlockEnd'), true);
+
+        // override the parent with the correct one
+        $module->setNode('parent', $parent);
+
+        $this->parser->embedTemplate($module);
+
+        $stream->expect(Twig_Token::BLOCK_END_TYPE);
+
+        return new Twig_Node_Embed($module->getAttribute('filename'), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
+    }
+
+    public function decideBlockEnd(Twig_Token $token)
+    {
+        return $token->test('endembed');
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'embed';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Extends.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Extends.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Extends.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Extends.php Tue May 22 14:42:25 2012
@@ -0,0 +1,54 @@
+<?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.
+ */
+
+/**
+ * Extends a template by another one.
+ *
+ * <pre>
+ *  {% extends "base.html" %}
+ * </pre>
+ */
+class Twig_TokenParser_Extends extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        if (!$this->parser->isMainScope()) {
+            throw new Twig_Error_Syntax('Cannot extend from a block', $token->getLine());
+        }
+
+        if (null !== $this->parser->getParent()) {
+            throw new Twig_Error_Syntax('Multiple extends tags are forbidden', $token->getLine());
+        }
+        $this->parser->setParent($this->parser->getExpressionParser()->parseExpression());
+
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+
+        return null;
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'extends';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Filter.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Filter.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Filter.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Filter.php Tue May 22 14:42:25 2012
@@ -0,0 +1,61 @@
+<?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.
+ */
+
+/**
+ * Filters a section of a template by applying filters.
+ *
+ * <pre>
+ * {% filter upper %}
+ *  This text becomes uppercase
+ * {% endfilter %}
+ * </pre>
+ */
+class Twig_TokenParser_Filter extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $name = $this->parser->getVarName();
+        $ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), true, $token->getLine(), $this->getTag());
+
+        $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag());
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+
+        $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+
+        $block = new Twig_Node_Block($name, $body, $token->getLine());
+        $this->parser->setBlock($name, $block);
+
+        return new Twig_Node_Print($filter, $token->getLine(), $this->getTag());
+    }
+
+    public function decideBlockEnd(Twig_Token $token)
+    {
+        return $token->test('endfilter');
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'filter';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Flush.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Flush.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Flush.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Flush.php Tue May 22 14:42:25 2012
@@ -0,0 +1,42 @@
+<?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.
+ */
+
+/**
+ * Flushes the output to the client.
+ *
+ * @see flush()
+ */
+class Twig_TokenParser_Flush extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+
+        return new Twig_Node_Flush($token->getLine(), $this->getTag());
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'flush';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/For.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/For.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/For.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/For.php Tue May 22 14:42:25 2012
@@ -0,0 +1,89 @@
+<?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.
+ */
+
+/**
+ * Loops over each item of a sequence.
+ *
+ * <pre>
+ * <ul>
+ *  {% for user in users %}
+ *    <li>{{ user.username|e }}</li>
+ *  {% endfor %}
+ * </ul>
+ * </pre>
+ */
+class Twig_TokenParser_For extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $lineno = $token->getLine();
+        $targets = $this->parser->getExpressionParser()->parseAssignmentExpression();
+        $this->parser->getStream()->expect(Twig_Token::OPERATOR_TYPE, 'in');
+        $seq = $this->parser->getExpressionParser()->parseExpression();
+
+        $ifexpr = null;
+        if ($this->parser->getStream()->test(Twig_Token::NAME_TYPE, 'if')) {
+            $this->parser->getStream()->next();
+            $ifexpr = $this->parser->getExpressionParser()->parseExpression();
+        }
+
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+        $body = $this->parser->subparse(array($this, 'decideForFork'));
+        if ($this->parser->getStream()->next()->getValue() == 'else') {
+            $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+            $else = $this->parser->subparse(array($this, 'decideForEnd'), true);
+        } else {
+            $else = null;
+        }
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+
+        if (count($targets) > 1) {
+            $keyTarget = $targets->getNode(0);
+            $keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getLine());
+            $valueTarget = $targets->getNode(1);
+            $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
+        } else {
+            $keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno);
+            $valueTarget = $targets->getNode(0);
+            $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
+        }
+
+        return new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, $lineno, $this->getTag());
+    }
+
+    public function decideForFork(Twig_Token $token)
+    {
+        return $token->test(array('else', 'endfor'));
+    }
+
+    public function decideForEnd(Twig_Token $token)
+    {
+        return $token->test('endfor');
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'for';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/From.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/From.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/From.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/From.php Tue May 22 14:42:25 2012
@@ -0,0 +1,74 @@
+<?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.
+ */
+
+/**
+ * Imports macros.
+ *
+ * <pre>
+ *   {% from 'forms.html' import forms %}
+ * </pre>
+ */
+class Twig_TokenParser_From extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $macro = $this->parser->getExpressionParser()->parseExpression();
+        $stream = $this->parser->getStream();
+        $stream->expect('import');
+
+        $targets = array();
+        do {
+            $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
+
+            $alias = $name;
+            if ($stream->test('as')) {
+                $stream->next();
+
+                $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
+            }
+
+            $targets[$name] = $alias;
+
+            if (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
+                break;
+            }
+
+            $stream->next();
+        } while (true);
+
+        $stream->expect(Twig_Token::BLOCK_END_TYPE);
+
+        $node = new Twig_Node_Import($macro, new Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), $token->getLine(), $this->getTag());
+
+        foreach($targets as $name => $alias) {
+            $this->parser->addImportedFunction($alias, 'get'.$name, $node->getNode('var'));
+        }
+
+        return $node;
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'from';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/If.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/If.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/If.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/If.php Tue May 22 14:42:25 2012
@@ -0,0 +1,93 @@
+<?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.
+ */
+
+/**
+ * Tests a condition.
+ *
+ * <pre>
+ * {% if users %}
+ *  <ul>
+ *    {% for user in users %}
+ *      <li>{{ user.username|e }}</li>
+ *    {% endfor %}
+ *  </ul>
+ * {% endif %}
+ * </pre>
+ */
+class Twig_TokenParser_If extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $lineno = $token->getLine();
+        $expr = $this->parser->getExpressionParser()->parseExpression();
+        $this->parser->getStream()->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()) {
+                case 'else':
+                    $this->parser->getStream()->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);
+                    $body = $this->parser->subparse(array($this, 'decideIfFork'));
+                    $tests[] = $expr;
+                    $tests[] = $body;
+                    break;
+
+                case 'endif':
+                    $end = true;
+                    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);
+            }
+        }
+
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+
+        return new Twig_Node_If(new Twig_Node($tests), $else, $lineno, $this->getTag());
+    }
+
+    public function decideIfFork(Twig_Token $token)
+    {
+        return $token->test(array('elseif', 'else', 'endif'));
+    }
+
+    public function decideIfEnd(Twig_Token $token)
+    {
+        return $token->test(array('endif'));
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'if';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Import.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Import.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Import.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Import.php Tue May 22 14:42:25 2012
@@ -0,0 +1,47 @@
+<?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.
+ */
+
+/**
+ * Imports macros.
+ *
+ * <pre>
+ *   {% import 'forms.html' as forms %}
+ * </pre>
+ */
+class Twig_TokenParser_Import extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $macro = $this->parser->getExpressionParser()->parseExpression();
+        $this->parser->getStream()->expect('as');
+        $var = new Twig_Node_Expression_AssignName($this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(), $token->getLine());
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+
+        return new Twig_Node_Import($macro, $var, $token->getLine(), $this->getTag());
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'import';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Include.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Include.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Include.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Include.php Tue May 22 14:42:25 2012
@@ -0,0 +1,80 @@
+<?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.
+ */
+
+/**
+ * Includes a template.
+ *
+ * <pre>
+ *   {% include 'header.html' %}
+ *     Body
+ *   {% include 'footer.html' %}
+ * </pre>
+ */
+class Twig_TokenParser_Include extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $expr = $this->parser->getExpressionParser()->parseExpression();
+
+        list($variables, $only, $ignoreMissing) = $this->parseArguments();
+
+        return new Twig_Node_Include($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
+    }
+
+    protected function parseArguments()
+    {
+        $stream = $this->parser->getStream();
+
+        $ignoreMissing = false;
+        if ($stream->test(Twig_Token::NAME_TYPE, 'ignore')) {
+            $stream->next();
+            $stream->expect(Twig_Token::NAME_TYPE, 'missing');
+
+            $ignoreMissing = true;
+        }
+
+        $variables = null;
+        if ($stream->test(Twig_Token::NAME_TYPE, 'with')) {
+            $stream->next();
+
+            $variables = $this->parser->getExpressionParser()->parseExpression();
+        }
+
+        $only = false;
+        if ($stream->test(Twig_Token::NAME_TYPE, 'only')) {
+            $stream->next();
+
+            $only = true;
+        }
+
+        $stream->expect(Twig_Token::BLOCK_END_TYPE);
+
+        return array($variables, $only, $ignoreMissing);
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'include';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Macro.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Macro.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Macro.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Macro.php Tue May 22 14:42:25 2012
@@ -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.
+ */
+
+/**
+ * Defines a macro.
+ *
+ * <pre>
+ * {% macro input(name, value, type, size) %}
+ *    <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
+ * {% endmacro %}
+ * </pre>
+ */
+class Twig_TokenParser_Macro extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $lineno = $token->getLine();
+        $name = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue();
+
+        $arguments = $this->parser->getExpressionParser()->parseArguments();
+
+        $this->parser->getStream()->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 ($value != $name) {
+                throw new Twig_Error_Syntax(sprintf("Expected endmacro for macro '$name' (but %s given)", $value), $lineno);
+            }
+        }
+        $this->parser->popLocalScope();
+        $this->parser->getStream()->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()));
+
+        return null;
+    }
+
+    public function decideBlockEnd(Twig_Token $token)
+    {
+        return $token->test('endmacro');
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'macro';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Sandbox.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Sandbox.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Sandbox.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Sandbox.php Tue May 22 14:42:25 2012
@@ -0,0 +1,55 @@
+<?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 section of a template as untrusted code that must be evaluated in the sandbox mode.
+ *
+ * <pre>
+ * {% sandbox %}
+ *     {% include 'user.html' %}
+ * {% endsandbox %}
+ * </pre>
+ *
+ * @see http://www.twig-project.org/doc/api.html#sandbox-extension for details
+ */
+class Twig_TokenParser_Sandbox extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+        $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+
+        return new Twig_Node_Sandbox($body, $token->getLine(), $this->getTag());
+    }
+
+    public function decideBlockEnd(Twig_Token $token)
+    {
+        return $token->test('endsandbox');
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'sandbox';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Set.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Set.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Set.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Set.php Tue May 22 14:42:25 2012
@@ -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.
+ */
+
+/**
+ * Defines a variable.
+ *
+ * <pre>
+ *  {% set foo = 'foo' %}
+ *
+ *  {% set foo = [1, 2] %}
+ *
+ *  {% set foo = {'foo': 'bar'} %}
+ *
+ *  {% set foo = 'foo' ~ 'bar' %}
+ *
+ *  {% set foo, bar = 'foo', 'bar' %}
+ *
+ *  {% set foo %}Some content{% endset %}
+ * </pre>
+ */
+class Twig_TokenParser_Set extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $lineno = $token->getLine();
+        $stream = $this->parser->getStream();
+        $names = $this->parser->getExpressionParser()->parseAssignmentExpression();
+
+        $capture = false;
+        if ($stream->test(Twig_Token::OPERATOR_TYPE, '=')) {
+            $stream->next();
+            $values = $this->parser->getExpressionParser()->parseMultitargetExpression();
+
+            $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);
+            }
+        } 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);
+            }
+
+            $stream->expect(Twig_Token::BLOCK_END_TYPE);
+
+            $values = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
+            $stream->expect(Twig_Token::BLOCK_END_TYPE);
+        }
+
+        return new Twig_Node_Set($capture, $names, $values, $lineno, $this->getTag());
+    }
+
+    public function decideBlockEnd(Twig_Token $token)
+    {
+        return $token->test('endset');
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'set';
+    }
+}

Added: logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Spaceless.php
URL: http://svn.apache.org/viewvc/logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Spaceless.php?rev=1341499&view=auto
==============================================================================
--- logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Spaceless.php (added)
+++ logging/site/branches/experimental-twig-textile/libs/Twig/lib/Twig/TokenParser/Spaceless.php Tue May 22 14:42:25 2012
@@ -0,0 +1,59 @@
+<?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.
+ */
+
+/**
+ * Remove whitespaces between HTML tags.
+ *
+ * <pre>
+ * {% spaceless %}
+ *      <div>
+ *          <strong>foo</strong>
+ *      </div>
+ * {% endspaceless %}
+ *
+ * {# output will be <div><strong>foo</strong></div> #}
+ * </pre>
+ */
+class Twig_TokenParser_Spaceless extends Twig_TokenParser
+{
+    /**
+     * Parses a token and returns a node.
+     *
+     * @param Twig_Token $token A Twig_Token instance
+     *
+     * @return Twig_NodeInterface A Twig_NodeInterface instance
+     */
+    public function parse(Twig_Token $token)
+    {
+        $lineno = $token->getLine();
+
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+        $body = $this->parser->subparse(array($this, 'decideSpacelessEnd'), true);
+        $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+
+        return new Twig_Node_Spaceless($body, $lineno, $this->getTag());
+    }
+
+    public function decideSpacelessEnd(Twig_Token $token)
+    {
+        return $token->test('endspaceless');
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @return string The tag name
+     */
+    public function getTag()
+    {
+        return 'spaceless';
+    }
+}