changeset 11278:7df88cdf47fd

revset: add support for prefix and suffix versions of : and ::
author Matt Mackall <mpm@selenic.com>
date Wed, 02 Jun 2010 14:07:46 -0500
parents 2698a95f3f1b
children 62ccf4cd6e7f
files mercurial/parser.py mercurial/revset.py
diffstat 2 files changed, 39 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/parser.py	Tue Jun 01 11:18:57 2010 -0500
+++ b/mercurial/parser.py	Wed Jun 02 14:07:46 2010 -0500
@@ -23,7 +23,10 @@
     def _advance(self):
         'advance the tokenizer'
         t = self.current
-        self.current = self._iter.next()
+        try:
+            self.current = self._iter.next()
+        except StopIteration:
+            pass
         return t
     def _match(self, m):
         'make sure the tokenizer matches an end condition'
@@ -49,17 +52,23 @@
         # gather tokens until we meet a lower binding strength
         while bind < self._elements[self.current[0]][0]:
             token, value = self._advance()
-            # handle infix rules
-            infix = self._elements[token][2]
-            if len(infix) == 3 and infix[2] == self.current[0]:
-                self._match(infix[2])
-                expr = (infix[0], expr, (None))
+            e = self._elements[token]
+            # check for suffix - next token isn't a valid prefix
+            if len(e) == 4 and not self._elements[self.current[0]][1]:
+                suffix = e[3]
+                expr = (suffix[0], expr)
             else:
-                if not infix[0]:
-                    raise SyntaxError("not an infix")
-                expr = (infix[0], expr, self._parse(infix[1]))
-                if len(infix) == 3:
+                # handle infix rules
+                infix = self._elements[token][2]
+                if len(infix) == 3 and infix[2] == self.current[0]:
                     self._match(infix[2])
+                    expr = (infix[0], expr, (None))
+                else:
+                    if not infix[0]:
+                        raise SyntaxError("not an infix")
+                    expr = (infix[0], expr, self._parse(infix[1]))
+                    if len(infix) == 3:
+                        self._match(infix[2])
         return expr
     def parse(self, message):
         'generate a parse tree from a message'
--- a/mercurial/revset.py	Tue Jun 01 11:18:57 2010 -0500
+++ b/mercurial/revset.py	Wed Jun 02 14:07:46 2010 -0500
@@ -12,8 +12,11 @@
 elements = {
     "(": (20, ("group", 1, ")"), ("func", 1, ")")),
     "-": (19, ("negate", 19), ("minus", 19)),
-    "..": (17, None, ("dagrange", 17)),
-    ":": (15, None, ("range", 15)),
+    "::": (17, ("dagrangepre", 17), ("dagrange", 17),
+           ("dagrangepost", 17)),
+    "..": (17, ("dagrangepre", 17), ("dagrange", 17),
+           ("dagrangepost", 17)),
+    ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
     "not": (10, ("not", 10)),
     "!": (10, ("not", 10)),
     "and": (5, None, ("and", 5)),
@@ -36,11 +39,14 @@
         c = program[pos]
         if c.isspace(): # skip inter-token whitespace
             pass
-        elif c in "():,-|&+!": # handle simple operators
-            yield (c, None)
+        elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
+            yield ('::', None)
+            pos += 1 # skip ahead
         elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
             yield ('..', None)
             pos += 1 # skip ahead
+        elif c in "():,-|&+!": # handle simple operators
+            yield (c, None)
         elif c in '"\'': # handle quoted strings
             pos += 1
             s = pos
@@ -126,6 +132,12 @@
         return range(m, n + 1)
     return range(m, n - 1, -1)
 
+def rangepreset(repo, subset, x):
+    return range(0, getset(repo, subset, x)[-1] + 1)
+
+def rangepostset(repo, subset, x):
+    return range(getset(repo, subset, x)[0], len(repo))
+
 def dagrangeset(repo, subset, x, y):
     return andset(repo, subset,
                   ('func', ('symbol', 'descendants'), x),
@@ -469,7 +481,11 @@
     "negate": negate,
     "minus": minusset,
     "range": rangeset,
+    "rangepre": rangepreset,
+    "rangepost": rangepostset,
     "dagrange": dagrangeset,
+    "dagrangepre": ancestors,
+    "dagrangepost": descendants,
     "string": stringset,
     "symbol": symbolset,
     "and": andset,