revset: extract tree transformation from optimize()
authorYuya Nishihara <yuya@tcha.org>
Sun, 07 Aug 2016 14:35:03 +0900
changeset 29904 e4b4168a4f1c
parent 29903 fe81c953f369
child 29905 371c2a39eead
revset: extract tree transformation from optimize() This patch separates the simple tree transformation from the optimization step, which is called as _analyze() since I'll extend this function to infer ordering flags. I want to avoid making _optimize() more complicated. This will also allow us to evaluate unoptimized tree.
mercurial/revset.py
--- a/mercurial/revset.py	Sun Sep 04 17:19:44 2016 +0900
+++ b/mercurial/revset.py	Sun Aug 07 14:35:03 2016 +0900
@@ -2342,7 +2342,68 @@
 
     return (op,) + tuple(_fixops(y) for y in x[1:])
 
+def _analyze(x):
+    """Transform raw parsed tree to evaluatable tree which can be fed to
+    optimize() or getset()
+
+    All pseudo operations should be mapped to real operations or functions
+    defined in methods or symbols table respectively.
+    """
+    if x is None:
+        return x
+
+    op = x[0]
+    if op == 'minus':
+        return _analyze(('and', x[1], ('not', x[2])))
+    elif op == 'only':
+        t = ('func', ('symbol', 'only'), ('list', x[1], x[2]))
+        return _analyze(t)
+    elif op == 'onlypost':
+        return _analyze(('func', ('symbol', 'only'), x[1]))
+    elif op == 'dagrangepre':
+        return _analyze(('func', ('symbol', 'ancestors'), x[1]))
+    elif op == 'dagrangepost':
+        return _analyze(('func', ('symbol', 'descendants'), x[1]))
+    elif op == 'rangeall':
+        return _analyze(('range', ('string', '0'), ('string', 'tip')))
+    elif op == 'rangepre':
+        return _analyze(('range', ('string', '0'), x[1]))
+    elif op == 'rangepost':
+        return _analyze(('range', x[1], ('string', 'tip')))
+    elif op == 'negate':
+        s = getstring(x[1], _("can't negate that"))
+        return _analyze(('string', '-' + s))
+    elif op in ('string', 'symbol'):
+        return x
+    elif op == 'and':
+        ta = _analyze(x[1])
+        tb = _analyze(x[2])
+        return (op, ta, tb)
+    elif op == 'or':
+        return (op,) + tuple(_analyze(y) for y in x[1:])
+    elif op == 'not':
+        return (op, _analyze(x[1]))
+    elif op == 'parentpost':
+        return (op, _analyze(x[1]))
+    elif op == 'group':
+        return _analyze(x[1])
+    elif op in ('dagrange', 'range', 'parent', 'ancestor'):
+        ta = _analyze(x[1])
+        tb = _analyze(x[2])
+        return (op, ta, tb)
+    elif op == 'list':
+        return (op,) + tuple(_analyze(y) for y in x[1:])
+    elif op == 'keyvalue':
+        return (op, x[1], _analyze(x[2]))
+    elif op == 'func':
+        return (op, x[1], _analyze(x[2]))
+    raise ValueError('invalid operator %r' % op)
+
 def _optimize(x, small):
+    """Optimize evaluatable tree
+
+    All pseudo operations should be transformed beforehand.
+    """
     if x is None:
         return 0, x
 
@@ -2351,27 +2412,7 @@
         smallbonus = .5
 
     op = x[0]
-    if op == 'minus':
-        return _optimize(('and', x[1], ('not', x[2])), small)
-    elif op == 'only':
-        t = ('func', ('symbol', 'only'), ('list', x[1], x[2]))
-        return _optimize(t, small)
-    elif op == 'onlypost':
-        return _optimize(('func', ('symbol', 'only'), x[1]), small)
-    elif op == 'dagrangepre':
-        return _optimize(('func', ('symbol', 'ancestors'), x[1]), small)
-    elif op == 'dagrangepost':
-        return _optimize(('func', ('symbol', 'descendants'), x[1]), small)
-    elif op == 'rangeall':
-        return _optimize(('range', ('string', '0'), ('string', 'tip')), small)
-    elif op == 'rangepre':
-        return _optimize(('range', ('string', '0'), x[1]), small)
-    elif op == 'rangepost':
-        return _optimize(('range', x[1], ('string', 'tip')), small)
-    elif op == 'negate':
-        s = getstring(x[1], _("can't negate that"))
-        return _optimize(('string', '-' + s), small)
-    elif op in ('string', 'symbol'):
+    if op in ('string', 'symbol'):
         return smallbonus, x # single revisions are small
     elif op == 'and':
         wa, ta = _optimize(x[1], True)
@@ -2432,8 +2473,6 @@
     elif op == 'parentpost':
         o = _optimize(x[1], small)
         return o[0], (op, o[1])
-    elif op == 'group':
-        return _optimize(x[1], small)
     elif op in ('dagrange', 'range', 'parent', 'ancestor'):
         wa, ta = _optimize(x[1], small)
         wb, tb = _optimize(x[2], small)
@@ -2466,6 +2505,7 @@
     raise ValueError('invalid operator %r' % op)
 
 def optimize(tree):
+    tree = _analyze(tree)
     _weight, newtree = _optimize(tree, small=True)
     return newtree