# HG changeset patch # User Yuya Nishihara # Date 1454424589 -32400 # Node ID b19d8d5d6b514c90d37204020f0935bd97fa4d1f # Parent a583789836871a53fe1654509497e4a65f772553 revset: flatten chained 'list' operations (aka function args) (issue5072) 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 -r a58378983687 -r b19d8d5d6b51 mercurial/revset.py --- a/mercurial/revset.py Fri Feb 05 19:40:57 2016 +0100 +++ b/mercurial/revset.py Tue Feb 02 23:49:49 2016 +0900 @@ -319,7 +319,7 @@ 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 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -r a58378983687 -r b19d8d5d6b51 tests/test-glog.t --- a/tests/test-glog.t Fri Feb 05 19:40:57 2016 +0100 +++ b/tests/test-glog.t Tue Feb 02 23:49:49 2016 +0900 @@ -1602,11 +1602,9 @@ (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 @@ (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 @@ (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 @@ (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 @@ (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 @@ (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 @@ (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 @@ (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 @@ (func ('symbol', '_matchfiles') (list - (list - ('string', 'r:') - ('string', 'd:relpath')) + ('string', 'r:') + ('string', 'd:relpath') ('string', 'p:.')))) $ testlog ../b [] diff -r a58378983687 -r b19d8d5d6b51 tests/test-revset.t --- a/tests/test-revset.t Fri Feb 05 19:40:57 2016 +0100 +++ b/tests/test-revset.t Tue Feb 02 23:49:49 2016 +0900 @@ -1168,6 +1168,14 @@ 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 @@ (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 @@ (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 @@ (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 @@ (func ('symbol', 'cat4') (list - (list - (list - ('symbol', '278') - ('string', '5f5')) - ('symbol', '1ee')) + ('symbol', '278') + ('string', '5f5') + ('symbol', '1ee') ('string', 'ce5'))) (_concat (_concat