diff mercurial/templater.py @ 25002:829faf8ab605

templater: tokenize decimal integer literal (issue4638) (BC) Before this patch, we had to quote integer literals to pass to template functions. It was error-prone, so we should allow "word(0, x)" syntax. Currently only decimal integers are allowed. It's easy to support 0x, 0b and 0 prefixes, but I don't think they are useful. This patch assumes that template keywords and names defined in map files do not start with digits, except for positional variables seen in the schemes extension.
author Yuya Nishihara <yuya@tcha.org>
date Fri, 01 May 2015 20:43:55 +0900
parents 9668c1a433b3
children 5e584edbb211
line wrap: on
line diff
--- a/mercurial/templater.py	Sat May 02 18:05:04 2015 +0900
+++ b/mercurial/templater.py	Fri May 01 20:43:55 2015 +0900
@@ -20,6 +20,7 @@
     "|": (5, None, ("|", 5)),
     "%": (6, None, ("%", 6)),
     ")": (0, None, None),
+    "integer": (0, ("integer",), None),
     "symbol": (0, ("symbol",), None),
     "string": (0, ("string",), None),
     "rawstring": (0, ("rawstring",), None),
@@ -59,6 +60,20 @@
                 pos += 1
             else:
                 raise error.ParseError(_("unterminated string"), s)
+        elif c.isdigit() or c == '-':
+            s = pos
+            if c == '-': # simply take negate operator as part of integer
+                pos += 1
+            if pos >= end or not program[pos].isdigit():
+                raise error.ParseError(_("integer literal without digits"), s)
+            pos += 1
+            while pos < end:
+                d = program[pos]
+                if not d.isdigit():
+                    break
+                pos += 1
+            yield ('integer', program[s:pos], s)
+            pos -= 1
         elif c.isalnum() or c in '_':
             s = pos
             pos += 1
@@ -135,6 +150,9 @@
         return context._load(exp[1])
     raise error.ParseError(_("expected template specifier"))
 
+def runinteger(context, mapping, data):
+    return int(data)
+
 def runstring(context, mapping, data):
     return data.decode("string-escape")
 
@@ -567,6 +585,7 @@
 
 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
 exprmethods = {
+    "integer": lambda e, c: (runinteger, e[1]),
     "string": lambda e, c: (runstring, e[1]),
     "rawstring": lambda e, c: (runrawstring, e[1]),
     "symbol": lambda e, c: (runsymbol, e[1]),
@@ -579,6 +598,7 @@
 
 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
 methods = exprmethods.copy()
+methods["integer"] = exprmethods["symbol"]  # '{1}' as variable
 
 funcs = {
     "date": date,