--- a/mercurial/parser.py Wed May 27 17:28:55 2015 -0500
+++ b/mercurial/parser.py Sun Apr 26 18:05:23 2015 +0900
@@ -108,3 +108,80 @@
_prettyformat(tree, leafnodes, 0, lines)
output = '\n'.join((' ' * l + s) for l, s in lines)
return output
+
+def simplifyinfixops(tree, targetnodes):
+ """Flatten chained infix operations to reduce usage of Python stack
+
+ >>> def f(tree):
+ ... print prettyformat(simplifyinfixops(tree, ('or',)), ('symbol',))
+ >>> f(('or',
+ ... ('or',
+ ... ('symbol', '1'),
+ ... ('symbol', '2')),
+ ... ('symbol', '3')))
+ (or
+ ('symbol', '1')
+ ('symbol', '2')
+ ('symbol', '3'))
+ >>> f(('func',
+ ... ('symbol', 'p1'),
+ ... ('or',
+ ... ('or',
+ ... ('func',
+ ... ('symbol', 'sort'),
+ ... ('list',
+ ... ('or',
+ ... ('or',
+ ... ('symbol', '1'),
+ ... ('symbol', '2')),
+ ... ('symbol', '3')),
+ ... ('negate',
+ ... ('symbol', 'rev')))),
+ ... ('and',
+ ... ('symbol', '4'),
+ ... ('group',
+ ... ('or',
+ ... ('or',
+ ... ('symbol', '5'),
+ ... ('symbol', '6')),
+ ... ('symbol', '7'))))),
+ ... ('symbol', '8'))))
+ (func
+ ('symbol', 'p1')
+ (or
+ (func
+ ('symbol', 'sort')
+ (list
+ (or
+ ('symbol', '1')
+ ('symbol', '2')
+ ('symbol', '3'))
+ (negate
+ ('symbol', 'rev'))))
+ (and
+ ('symbol', '4')
+ (group
+ (or
+ ('symbol', '5')
+ ('symbol', '6')
+ ('symbol', '7'))))
+ ('symbol', '8')))
+ """
+ if not isinstance(tree, tuple):
+ return tree
+ op = tree[0]
+ if op not in targetnodes:
+ return (op,) + tuple(simplifyinfixops(x, targetnodes) for x in tree[1:])
+
+ # walk down left nodes taking each right node. no recursion to left nodes
+ # because infix operators are left-associative, i.e. left tree is deep.
+ # e.g. '1 + 2 + 3' -> (+ (+ 1 2) 3) -> (+ 1 2 3)
+ simplified = []
+ x = tree
+ while x[0] == op:
+ l, r = x[1:]
+ simplified.append(simplifyinfixops(r, targetnodes))
+ x = l
+ simplified.append(simplifyinfixops(x, targetnodes))
+ simplified.append(op)
+ return tuple(reversed(simplified))