[PATCH STABLE] revset: flatten chained 'list' operations (aka function args) (issue5072)
Augie Fackler
raf at durin42.com
Fri Feb 5 22:10:49 UTC 2016
On Fri, Feb 05, 2016 at 12:08:52AM +0900, Yuya Nishihara wrote:
> # HG changeset patch
> # User Yuya Nishihara <yuya at tcha.org>
> # Date 1454424589 -32400
> # Tue Feb 02 23:49:49 2016 +0900
> # Branch stable
> # Node ID 016bccc8a86965cba08d3d6ad77638dfb81cd5e0
> # Parent c58c4683e2b71a18d6b82f2e8c6e7607b1079bef
> revset: flatten chained 'list' operations (aka function args) (issue5072)
Queued for stable, thanks.
>
> Internal _matchfiles() function can take bunch of arguments, which would
> lead to a maximum recursion depth error. This patch avoids the excessive
> stack use by flattening 'list' nodes beforehand.
>
> Since getlist() no longer takes a nested 'list' nodes, _parsealiasdecl()
> also needs to flatten argument list, "aliasname($1, $2, ...)".
>
> diff --git a/mercurial/revset.py b/mercurial/revset.py
> --- a/mercurial/revset.py
> +++ b/mercurial/revset.py
> @@ -319,7 +319,7 @@ def getlist(x):
> if not x:
> return []
> if x[0] == 'list':
> - return getlist(x[1]) + [x[2]]
> + return list(x[1:])
> return [x]
>
> def getargs(x, min, max, err):
> @@ -448,7 +448,7 @@ def orset(repo, subset, *xs):
> def notset(repo, subset, x):
> return subset - getset(repo, subset, x)
>
> -def listset(repo, subset, a, b):
> +def listset(repo, subset, *xs):
> raise error.ParseError(_("can't use a list in this context"),
> hint=_('see hg help "revsets.x or y"'))
>
> @@ -2252,7 +2252,7 @@ def optimize(x, small):
> return o[0], (op, o[1])
> elif op == 'group':
> return optimize(x[1], small)
> - elif op in 'dagrange range list parent ancestorspec':
> + elif op in 'dagrange range parent ancestorspec':
> if op == 'parent':
> # x^:y means (x^) : y, not x ^ (:y)
> post = ('parentpost', x[1])
> @@ -2264,6 +2264,9 @@ def optimize(x, small):
> wa, ta = optimize(x[1], small)
> wb, tb = optimize(x[2], small)
> return wa + wb, (op, ta, tb)
> + elif op == 'list':
> + ws, ts = zip(*(optimize(y, small) for y in x[1:]))
> + return sum(ws), (op,) + ts
> elif op == 'func':
> f = getstring(x[1], _("not a symbol"))
> wa, ta = optimize(x[2], small)
> @@ -2365,6 +2368,7 @@ def _parsealiasdecl(decl):
> tree, pos = p.parse(_tokenizealias(decl))
> if (pos != len(decl)):
> raise error.ParseError(_('invalid token'), pos)
> + tree = parser.simplifyinfixops(tree, ('list',))
>
> if isvalidsymbol(tree):
> # "name = ...." style
> @@ -2455,7 +2459,7 @@ def _parsealiasdefn(defn, args):
> tree, pos = p.parse(tokenizedefn(defn))
> if pos != len(defn):
> raise error.ParseError(_('invalid token'), pos)
> - return parser.simplifyinfixops(tree, ('or',))
> + return parser.simplifyinfixops(tree, ('list', 'or'))
>
> class revsetalias(object):
> # whether own `error` information is already shown or not.
> @@ -2586,7 +2590,7 @@ def parse(spec, lookup=None):
> tree, pos = p.parse(tokenize(spec, lookup=lookup))
> if pos != len(spec):
> raise error.ParseError(_("invalid token"), pos)
> - return parser.simplifyinfixops(tree, ('or',))
> + return parser.simplifyinfixops(tree, ('list', 'or'))
>
> def posttreebuilthook(tree, repo):
> # hook for extensions to execute code on the optimized tree
> diff --git a/tests/test-glog.t b/tests/test-glog.t
> --- a/tests/test-glog.t
> +++ b/tests/test-glog.t
> @@ -1602,11 +1602,9 @@ Test falling back to slow path for non-e
> (func
> ('symbol', '_matchfiles')
> (list
> - (list
> - (list
> - ('string', 'r:')
> - ('string', 'd:relpath'))
> - ('string', 'p:a'))
> + ('string', 'r:')
> + ('string', 'd:relpath')
> + ('string', 'p:a')
> ('string', 'p:c'))))
>
> Test multiple --include/--exclude/paths
> @@ -1617,19 +1615,13 @@ Test multiple --include/--exclude/paths
> (func
> ('symbol', '_matchfiles')
> (list
> - (list
> - (list
> - (list
> - (list
> - (list
> - (list
> - ('string', 'r:')
> - ('string', 'd:relpath'))
> - ('string', 'p:a'))
> - ('string', 'p:e'))
> - ('string', 'i:a'))
> - ('string', 'i:e'))
> - ('string', 'x:b'))
> + ('string', 'r:')
> + ('string', 'd:relpath')
> + ('string', 'p:a')
> + ('string', 'p:e')
> + ('string', 'i:a')
> + ('string', 'i:e')
> + ('string', 'x:b')
> ('string', 'x:e'))))
>
> Test glob expansion of pats
> @@ -1668,9 +1660,8 @@ Test --follow on a directory
> (func
> ('symbol', '_matchfiles')
> (list
> - (list
> - ('string', 'r:')
> - ('string', 'd:relpath'))
> + ('string', 'r:')
> + ('string', 'd:relpath')
> ('string', 'p:dir')))))
> $ hg up -q tip
>
> @@ -1693,9 +1684,8 @@ Test --follow and patterns
> (func
> ('symbol', '_matchfiles')
> (list
> - (list
> - ('string', 'r:')
> - ('string', 'd:relpath'))
> + ('string', 'r:')
> + ('string', 'd:relpath')
> ('string', 'p:glob:*')))))
>
> Test --follow on a single rename
> @@ -1836,9 +1826,8 @@ Test "set:..." and parent revision
> (func
> ('symbol', '_matchfiles')
> (list
> - (list
> - ('string', 'r:')
> - ('string', 'd:relpath'))
> + ('string', 'r:')
> + ('string', 'd:relpath')
> ('string', 'p:set:copied()'))))
> $ testlog --include "set:copied()"
> []
> @@ -1846,9 +1835,8 @@ Test "set:..." and parent revision
> (func
> ('symbol', '_matchfiles')
> (list
> - (list
> - ('string', 'r:')
> - ('string', 'd:relpath'))
> + ('string', 'r:')
> + ('string', 'd:relpath')
> ('string', 'i:set:copied()'))))
> $ testlog -r "sort(file('set:copied()'), -rev)"
> ["sort(file('set:copied()'), -rev)"]
> @@ -1865,9 +1853,8 @@ Test --removed
> (func
> ('symbol', '_matchfiles')
> (list
> - (list
> - ('string', 'r:')
> - ('string', 'd:relpath'))
> + ('string', 'r:')
> + ('string', 'd:relpath')
> ('string', 'p:a'))))
> $ testlog --removed --follow a
> []
> @@ -1879,9 +1866,8 @@ Test --removed
> (func
> ('symbol', '_matchfiles')
> (list
> - (list
> - ('string', 'r:')
> - ('string', 'd:relpath'))
> + ('string', 'r:')
> + ('string', 'd:relpath')
> ('string', 'p:a')))))
>
> Test --patch and --stat with --follow and --follow-first
> @@ -2271,9 +2257,8 @@ Test subdir
> (func
> ('symbol', '_matchfiles')
> (list
> - (list
> - ('string', 'r:')
> - ('string', 'd:relpath'))
> + ('string', 'r:')
> + ('string', 'd:relpath')
> ('string', 'p:.'))))
> $ testlog ../b
> []
> diff --git a/tests/test-revset.t b/tests/test-revset.t
> --- a/tests/test-revset.t
> +++ b/tests/test-revset.t
> @@ -1168,6 +1168,14 @@ test ',' in `_list`
> hg: parse error: can't use a list in this context
> (see hg help "revsets.x or y")
> [255]
> + $ try '0,1,2'
> + (list
> + ('symbol', '0')
> + ('symbol', '1')
> + ('symbol', '2'))
> + hg: parse error: can't use a list in this context
> + (see hg help "revsets.x or y")
> + [255]
>
> test that chained `or` operations make balanced addsets
>
> @@ -1717,13 +1725,12 @@ test chained `or` operations are flatten
> (func
> ('symbol', 'chainedorops')
> (list
> - (list
> - (range
> - ('symbol', '0')
> - ('symbol', '1'))
> - (range
> - ('symbol', '1')
> - ('symbol', '2')))
> + (range
> + ('symbol', '0')
> + ('symbol', '1'))
> + (range
> + ('symbol', '1')
> + ('symbol', '2'))
> (range
> ('symbol', '2')
> ('symbol', '3'))))
> @@ -1877,9 +1884,8 @@ far away.
> (func
> ('symbol', 'rs')
> (list
> - (list
> - ('symbol', '2')
> - ('symbol', 'data'))
> + ('symbol', '2')
> + ('symbol', 'data')
> ('symbol', '7')))
> hg: parse error: invalid number of arguments: 3
> [255]
> @@ -1887,13 +1893,11 @@ far away.
> (func
> ('symbol', 'rs4')
> (list
> - (list
> - (list
> - (or
> - ('symbol', '2')
> - ('symbol', '3'))
> - ('symbol', 'x'))
> - ('symbol', 'x'))
> + (or
> + ('symbol', '2')
> + ('symbol', '3'))
> + ('symbol', 'x')
> + ('symbol', 'x')
> ('symbol', 'date')))
> (func
> ('symbol', 'reverse')
> @@ -2055,11 +2059,9 @@ tests for concatenation of strings/symbo
> (func
> ('symbol', 'cat4')
> (list
> - (list
> - (list
> - ('symbol', '278')
> - ('string', '5f5'))
> - ('symbol', '1ee'))
> + ('symbol', '278')
> + ('string', '5f5')
> + ('symbol', '1ee')
> ('string', 'ce5')))
> (_concat
> (_concat
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
More information about the Mercurial-devel
mailing list