Mercurial > hg
changeset 25306:c87b05925054
parser: add helper to reduce nesting of chained infix operations
This will be used to avoid stack overflow caused by chained 'or' operations
in revset.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sun, 26 Apr 2015 18:05:23 +0900 |
parents | 9bc11716bc86 |
children | 4d1e56b29a91 |
files | mercurial/parser.py tests/test-doctest.py |
diffstat | 2 files changed, 78 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- 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))
--- a/tests/test-doctest.py Wed May 27 17:28:55 2015 -0500 +++ b/tests/test-doctest.py Sun Apr 26 18:05:23 2015 +0900 @@ -21,6 +21,7 @@ testmod('mercurial.minirst') testmod('mercurial.patch') testmod('mercurial.pathutil') +testmod('mercurial.parser') testmod('mercurial.revset') testmod('mercurial.store') testmod('mercurial.subrepo')