fixed negative number lexing
authorFabien Potencier <fabien.potencier@gmail.com>
Sat, 11 Oct 2014 22:26:35 +0000 (00:26 +0200)
committerFabien Potencier <fabien.potencier@gmail.com>
Tue, 14 Oct 2014 16:08:14 +0000 (18:08 +0200)
CHANGELOG
lib/Twig/Lexer.php
test/Twig/Tests/Fixtures/expressions/negative_numbers.test [new file with mode: 0644]
test/Twig/Tests/LexerTest.php

index 9d136c1..d41ea1d 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,6 @@
 * 1.16.2 (2014-XX-XX)
 
+ * fixed lexing of negative numbers
  * fixed macros when using an argument named like a PHP super global (like GET or POST)
  * fixed date_modify when working with DateTimeImmutable
  * optimized for loops
index ad3ec7d..43d6daa 100644 (file)
@@ -40,7 +40,7 @@ class Twig_Lexer implements Twig_LexerInterface
     const STATE_INTERPOLATION   = 4;
 
     const REGEX_NAME            = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
-    const REGEX_NUMBER          = '/[0-9]+(?:\.[0-9]+)?/A';
+    const REGEX_NUMBER          = '/\-?[0-9]+(?:\.[0-9]+)?/A';
     const REGEX_STRING          = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
     const REGEX_DQ_STRING_DELIM = '/"/A';
     const REGEX_DQ_STRING_PART  = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
@@ -228,8 +228,17 @@ class Twig_Lexer implements Twig_LexerInterface
             }
         }
 
+        // numbers
+        if (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) {
+            $number = (float) $match[0];  // floats
+            if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) {
+                $number = (int) $match[0]; // integers lower than the maximum
+            }
+            $this->pushToken(Twig_Token::NUMBER_TYPE, $number);
+            $this->moveCursor($match[0]);
+        }
         // operators
-        if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
+        elseif (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
             $this->pushToken(Twig_Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0]));
             $this->moveCursor($match[0]);
         }
@@ -238,15 +247,6 @@ class Twig_Lexer implements Twig_LexerInterface
             $this->pushToken(Twig_Token::NAME_TYPE, $match[0]);
             $this->moveCursor($match[0]);
         }
-        // numbers
-        elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) {
-            $number = (float) $match[0];  // floats
-            if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) {
-                $number = (int) $match[0]; // integers lower than the maximum
-            }
-            $this->pushToken(Twig_Token::NUMBER_TYPE, $number);
-            $this->moveCursor($match[0]);
-        }
         // punctuation
         elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
             // opening bracket
diff --git a/test/Twig/Tests/Fixtures/expressions/negative_numbers.test b/test/Twig/Tests/Fixtures/expressions/negative_numbers.test
new file mode 100644 (file)
index 0000000..3f7afda
--- /dev/null
@@ -0,0 +1,13 @@
+--TEST--
+Twig manages negative numbers correctly
+--TEMPLATE--
+{% import _self as macros %}
+{{ macros.negative_number1() }}
+{{ macros.negative_number2() }}
+{% macro negative_number1(nb=-1) %}{{ nb }}{% endmacro %}
+{% macro negative_number2(nb = -1) %}{{ nb }}{% endmacro %}
+--DATA--
+return array()
+--EXPECT--
+-1
+-1
index c4d7083..74e8397 100644 (file)
@@ -260,6 +260,23 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase
         $stream->expect(Twig_Token::OPERATOR_TYPE, 'and');
     }
 
+    public function testNegativeNumbers()
+    {
+        $template = "{{ -3 }}{{ 1 - 2 }}";
+
+        $lexer = new Twig_Lexer(new Twig_Environment());
+        $stream = $lexer->tokenize($template);
+        $stream->expect(Twig_Token::VAR_START_TYPE);
+        $stream->expect(Twig_Token::NUMBER_TYPE, -3);
+        $stream->expect(Twig_Token::VAR_END_TYPE);
+
+        $stream->expect(Twig_Token::VAR_START_TYPE);
+        $stream->expect(Twig_Token::NUMBER_TYPE, 1);
+        $stream->expect(Twig_Token::OPERATOR_TYPE, '-');
+        $stream->expect(Twig_Token::NUMBER_TYPE, 2);
+        $stream->expect(Twig_Token::VAR_END_TYPE);
+    }
+
     /**
      * @expectedException Twig_Error_Syntax
      * @expectedExceptionMessage Unclosed "variable" at line 3