changeset 41219:e5b227f41e4a

revset: extract parsing logic out of formatspec We want to be able to perform better handling of some input when running revset (eg: `repo.revs("%ld", somerevs)`). The first step is to be able to access some of the parsed content before it gets substituted. There are many possible different substitutions, we'll add support for them gradually. In this changeset we support none, we just split some logic in a sub function as a preparatory step.
author Boris Feld <boris.feld@octobus.net>
date Fri, 04 Jan 2019 02:29:04 +0100
parents 24a1f67bb75a
children 8d26026b3335
files mercurial/revsetlang.py
diffstat 1 files changed, 25 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/revsetlang.py	Thu Jan 10 15:23:58 2019 +0100
+++ b/mercurial/revsetlang.py	Fri Jan 04 02:29:04 2019 +0100
@@ -666,6 +666,23 @@
     >>> formatspec(b'%ls', [b'a', b"'"])
     "_list('a\\\\x00\\\\'')"
     '''
+    parsed = _parseargs(expr, args)
+    ret = []
+    for t, arg in parsed:
+        if t is None:
+            ret.append(arg)
+        else:
+            raise error.ProgrammingError("unknown revspec item type: %r" % t)
+    return b''.join(ret)
+
+def _parseargs(expr, args):
+    """parse the expression and replace all inexpensive args
+
+    return a list of tuple [(arg-type, arg-value)]
+
+    Arg-type can be:
+    * None: a string ready to be concatenated into a final spec
+    """
     expr = pycompat.bytestr(expr)
     argiter = iter(args)
     ret = []
@@ -673,16 +690,16 @@
     while pos < len(expr):
         q = expr.find('%', pos)
         if q < 0:
-            ret.append(expr[pos:])
+            ret.append((None, expr[pos:]))
             break
-        ret.append(expr[pos:q])
+        ret.append((None, expr[pos:q]))
         pos = q + 1
         try:
             d = expr[pos]
         except IndexError:
             raise error.ParseError(_('incomplete revspec format character'))
         if d == '%':
-            ret.append(d)
+            ret.append((None, d))
             pos += 1
             continue
 
@@ -692,19 +709,20 @@
             raise error.ParseError(_('missing argument for revspec'))
         f = _formatlistfuncs.get(d)
         if f:
-            # a list of some type
+            # a list of some type, might be expensive, do not replace
             pos += 1
             try:
                 d = expr[pos]
             except IndexError:
                 raise error.ParseError(_('incomplete revspec format character'))
             try:
-                ret.append(f(list(arg), d))
+                ret.append((None, f(list(arg), d)))
             except (TypeError, ValueError):
                 raise error.ParseError(_('invalid argument for revspec'))
         else:
+            # a single entry, not expensive, replace
             try:
-                ret.append(_formatargtype(d, arg))
+                ret.append((None, _formatargtype(d, arg)))
             except (TypeError, ValueError):
                 raise error.ParseError(_('invalid argument for revspec'))
         pos += 1
@@ -714,7 +732,7 @@
         raise error.ParseError(_('too many revspec arguments specified'))
     except StopIteration:
         pass
-    return ''.join(ret)
+    return ret
 
 def prettyformat(tree):
     return parser.prettyformat(tree, ('string', 'symbol'))