made operators configurable
authorFabien Potencier <fabien.potencier@gmail.com>
Fri, 26 Nov 2010 19:57:53 +0000 (20:57 +0100)
committerFabien Potencier <fabien.potencier@gmail.com>
Fri, 26 Nov 2010 19:57:53 +0000 (20:57 +0100)
lib/Twig/Environment.php
lib/Twig/ExpressionParser.php
lib/Twig/Extension.php
lib/Twig/Extension/Core.php
lib/Twig/ExtensionInterface.php
lib/Twig/Parser.php

index b8b6a9c..d03984b 100644 (file)
@@ -30,6 +30,8 @@ class Twig_Environment
     protected $runtimeInitialized;
     protected $loadedTemplates;
     protected $strictVariables;
+    protected $unaryOperators;
+    protected $binaryOperators;
 
     /**
      * Constructor.
@@ -414,6 +416,44 @@ class Twig_Environment
         return $this->tests;
     }
 
+    public function getUnaryOperators()
+    {
+        if (null === $this->unaryOperators) {
+            $this->initOperators();
+        }
+
+        return $this->unaryOperators;
+    }
+
+    public function getBinaryOperators()
+    {
+        if (null === $this->binaryOperators) {
+            $this->initOperators();
+        }
+
+        return $this->binaryOperators;
+    }
+
+    protected function initOperators()
+    {
+        $this->unaryOperators = array();
+        $this->binaryOperators = array();
+        foreach ($this->getExtensions() as $extension) {
+            $operators = $extension->getOperators();
+
+            if (!$operators) {
+                continue;
+            }
+
+            if (2 !== count($operators)) {
+                throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension)));
+            }
+
+            $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
+            $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
+        }
+    }
+
     protected function writeCacheFile($file, $content)
     {
         $tmpFile = tempnam(dirname($file), basename($file));
index 80f8d1d..a014c94 100644 (file)
@@ -30,47 +30,11 @@ class Twig_ExpressionParser
     protected $unaryOperators;
     protected $binaryOperators;
 
-    public function __construct(Twig_Parser $parser)
+    public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators)
     {
         $this->parser = $parser;
-        $this->unaryOperators = $this->getUnaryOperators();
-        $this->binaryOperators = $this->getBinaryOperators();
-    }
-
-    public function getUnaryOperators()
-    {
-        return array(
-            'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
-            '-'   => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Neg'),
-            '+'   => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Pos'),
-        );
-    }
-
-    public function getBinaryOperators()
-    {
-        return array(
-            'or'     => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => self::OPERATOR_LEFT),
-            'and'    => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => self::OPERATOR_LEFT),
-            '=='     => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => self::OPERATOR_LEFT),
-            '!='     => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => self::OPERATOR_LEFT),
-            '<'      => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => self::OPERATOR_LEFT),
-            '>'      => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => self::OPERATOR_LEFT),
-            '>='     => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => self::OPERATOR_LEFT),
-            '<='     => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => self::OPERATOR_LEFT),
-            'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => self::OPERATOR_LEFT),
-            'in'     => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => self::OPERATOR_LEFT),
-            '+'      => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => self::OPERATOR_LEFT),
-            '-'      => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => self::OPERATOR_LEFT),
-            '~'      => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => self::OPERATOR_LEFT),
-            '*'      => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => self::OPERATOR_LEFT),
-            '/'      => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => self::OPERATOR_LEFT),
-            '//'     => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => self::OPERATOR_LEFT),
-            '%'      => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => self::OPERATOR_LEFT),
-            'is'     => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => self::OPERATOR_LEFT),
-            'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => self::OPERATOR_LEFT),
-            '..'     => array('precedence' => 110, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => self::OPERATOR_LEFT),
-            '**'     => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => self::OPERATOR_RIGHT),
-        );
+        $this->unaryOperators = $unaryOperators;
+        $this->binaryOperators = $binaryOperators;
     }
 
     public function parseExpression($precedence = 0)
@@ -82,7 +46,7 @@ class Twig_ExpressionParser
             $this->parser->getStream()->next();
 
             if (isset($op['callable'])) {
-                $expr = call_user_func($op['callable'], $expr);
+                $expr = call_user_func($op['callable'], $this->parser, $expr);
             } else {
                 $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
                 $class = $op['class'];
@@ -250,23 +214,6 @@ class Twig_ExpressionParser
         return $node;
     }
 
-    public function parseNotTestExpression($node)
-    {
-        return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine());
-    }
-
-    public function parseTestExpression($node)
-    {
-        $stream = $this->parser->getStream();
-        $name = $stream->expect(Twig_Token::NAME_TYPE);
-        $arguments = null;
-        if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
-            $arguments = $this->parseArguments($node);
-        }
-
-        return new Twig_Node_Expression_Test($node, $name->getValue(), $arguments, $this->parser->getCurrentToken()->getLine());
-    }
-
     public function parseSubscriptExpression($node)
     {
         $token = $this->parser->getStream()->next();
index dc1d34a..9294fc5 100644 (file)
@@ -60,4 +60,14 @@ abstract class Twig_Extension implements Twig_ExtensionInterface
     {
         return array();
     }
+
+    /**
+     * Returns a list of operators to add to the existing list.
+     *
+     * @return array An array of operators
+     */
+    public function getOperators()
+    {
+        return array();
+    }
 }
index e19fff5..cb3a110 100644 (file)
@@ -103,6 +103,62 @@ class Twig_Extension_Core extends Twig_Extension
     }
 
     /**
+     * Returns a list of operators to add to the existing list.
+     *
+     * @return array An array of operators
+     */
+    public function getOperators()
+    {
+        return array(
+            array(
+                'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
+                '-'   => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Neg'),
+                '+'   => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Pos'),
+            ),
+            array(
+                'or'     => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                'and'    => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '=='     => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '!='     => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '<'      => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '>'      => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '>='     => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '<='     => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                'in'     => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '+'      => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '-'      => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '~'      => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '*'      => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '/'      => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '//'     => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '%'      => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                'is'     => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '..'     => array('precedence' => 110, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
+                '**'     => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT),
+            ),
+        );
+    }
+
+    public function parseNotTestExpression($parser, $node)
+    {
+        return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine());
+    }
+
+    public function parseTestExpression($parser, $node)
+    {
+        $stream = $parser->getStream();
+        $name = $stream->expect(Twig_Token::NAME_TYPE);
+        $arguments = null;
+        if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
+            $arguments = $parser->getExpressionParser()->parseArguments($node);
+        }
+
+        return new Twig_Node_Expression_Test($node, $name->getValue(), $arguments, $parser->getCurrentToken()->getLine());
+    }
+
+    /**
      * Returns the name of the extension.
      *
      * @return string The extension name
index 69f9683..f3684f9 100644 (file)
@@ -55,6 +55,13 @@ interface Twig_ExtensionInterface
     public function getTests();
 
     /**
+     * Returns a list of operators to add to the existing list.
+     *
+     * @return array An array of operators
+     */
+    public function getOperators();
+
+    /**
      * Returns the name of the extension.
      *
      * @return string The extension name
index cb224d0..acc17e6 100644 (file)
@@ -50,7 +50,7 @@ class Twig_Parser implements Twig_ParserInterface
         $this->visitors = $this->env->getNodeVisitors();
 
         if (null === $this->expressionParser) {
-            $this->expressionParser = new Twig_ExpressionParser($this);
+            $this->expressionParser = new Twig_ExpressionParser($this, $this->env->getUnaryOperators(), $this->env->getBinaryOperators());
         }
 
         $this->stream = $stream;