changeset 14723:b9faf94ee196 stable

revset: fix aliases with 0 or more than 2 parameters The existing code seemed to have incorrect assumptions about how parameter lists are represented by the parser. Now the match and replace functions have been merged and simplified by using getlist().
author Mads Kiilerich <mads@kiilerich.com>
date Wed, 22 Jun 2011 01:55:00 +0200
parents b6dc362b051c
children b5c60df21b4b 2852933fc942
files mercurial/revset.py tests/test-revset.t
diffstat 2 files changed, 42 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/revset.py	Thu Jun 23 14:40:57 2011 +0200
+++ b/mercurial/revset.py	Wed Jun 22 01:55:00 2011 +0200
@@ -954,70 +954,46 @@
 
 class revsetalias(object):
     funcre = re.compile('^([^(]+)\(([^)]+)\)$')
-    args = ()
+    args = None
 
-    def __init__(self, token, value):
+    def __init__(self, name, value):
         '''Aliases like:
 
         h = heads(default)
         b($1) = ancestors($1) - ancestors(default)
         '''
-        if isinstance(token, tuple):
-            self.type, self.name = token
-        else:
-            m = self.funcre.search(token)
+        if isinstance(name, tuple): # parameter substitution
+            self.tree = name
+            self.replacement = value
+        else: # alias definition
+            m = self.funcre.search(name)
             if m:
-                self.type = 'func'
-                self.name = m.group(1)
+                self.tree = ('func', ('symbol', m.group(1)))
                 self.args = [x.strip() for x in m.group(2).split(',')]
+                for arg in self.args:
+                    value = value.replace(arg, repr(arg))
             else:
-                self.type = 'symbol'
-                self.name = token
+                self.tree = ('symbol', name)
 
-        if isinstance(value, str):
-            for arg in self.args:
-                value = value.replace(arg, repr(arg))
             self.replacement, pos = parse(value)
             if pos != len(value):
                 raise error.ParseError(_('invalid token'), pos)
-        else:
-            self.replacement = value
-
-    def match(self, tree):
-        if not tree:
-            return False
-        if tree == (self.type, self.name):
-            return True
-        if tree[0] != self.type:
-            return False
-        if len(tree) > 1 and tree[1] != ('symbol', self.name):
-            return False
-        # 'func' + funcname + args
-        if ((self.args and len(tree) != 3) or
-            (len(self.args) == 1 and tree[2][0] == 'list') or
-            (len(self.args) > 1 and (tree[2][0] != 'list' or
-                                     len(tree[2]) - 1 != len(self.args)))):
-            raise error.ParseError(_('invalid amount of arguments'),
-                                   len(tree) - 2)
-        return True
-
-    def replace(self, tree):
-        if tree == (self.type, self.name):
-            return self.replacement
-        result = self.replacement
-        def getsubtree(i):
-            if tree[2][0] == 'list':
-                return tree[2][i + 1]
-            return tree[i + 2]
-        for i, v in enumerate(self.args):
-            valalias = revsetalias(('string', v), getsubtree(i))
-            result = valalias.process(result)
-        return result
 
     def process(self, tree):
-        if self.match(tree):
-            return self.replace(tree)
         if isinstance(tree, tuple):
+            if self.args is None:
+                if tree == self.tree:
+                    return self.replacement
+            elif tree[:2] == self.tree:
+                l = getlist(tree[2])
+                if len(l) != len(self.args):
+                    raise error.ParseError(
+                        _('invalid number of arguments: %s') % len(l))
+                result = self.replacement
+                for a, v in zip(self.args, l):
+                    valalias = revsetalias(('string', a), v)
+                    result = valalias.process(result)
+                return result
             return tuple(map(self.process, tree))
         return tree
 
--- a/tests/test-revset.t	Thu Jun 23 14:40:57 2011 +0200
+++ b/tests/test-revset.t	Wed Jun 22 01:55:00 2011 +0200
@@ -420,6 +420,7 @@
   $ echo 'm = merge()' >> .hg/hgrc
   $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
   $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
+  $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
 
   $ try m
   ('symbol', 'm')
@@ -437,6 +438,23 @@
   ('func', ('symbol', 'reverse'), ('func', ('symbol', 'sort'), ('list', ('or', ('symbol', '2'), ('symbol', '3')), ('symbol', 'date'))))
   3
   2
+  $ try 'rs()'
+  ('func', ('symbol', 'rs'), None)
+  hg: parse error: invalid number of arguments: 0
+  [255]
+  $ try 'rs(2)'
+  ('func', ('symbol', 'rs'), ('symbol', '2'))
+  hg: parse error: invalid number of arguments: 1
+  [255]
+  $ try 'rs(2, data, 7)'
+  ('func', ('symbol', 'rs'), ('list', ('list', ('symbol', '2'), ('symbol', 'data')), ('symbol', '7')))
+  hg: parse error: invalid number of arguments: 3
+  [255]
+  $ try 'rs4(2 or 3, x, x, date)'
+  ('func', ('symbol', 'rs4'), ('list', ('list', ('list', ('or', ('symbol', '2'), ('symbol', '3')), ('symbol', 'x')), ('symbol', 'x')), ('symbol', 'date')))
+  ('func', ('symbol', 'reverse'), ('func', ('symbol', 'sort'), ('list', ('or', ('symbol', '2'), ('symbol', '3')), ('symbol', 'date'))))
+  3
+  2
 
 issue2549 - correct optimizations