revset: resolve ambiguity of x^:y before alias expansion
This is purely a parsing problem, which should be resolved before alias
expansion.
--- a/mercurial/revset.py Sat Aug 06 19:59:28 2016 +0900
+++ b/mercurial/revset.py Sat Aug 06 20:21:00 2016 +0900
@@ -2314,6 +2314,23 @@
and getsymbol(bases[1][1]) == 'ancestors'):
return ('list', revs[2], bases[1][2])
+def _fixops(x):
+ """Rewrite raw parsed tree to resolve ambiguous syntax which cannot be
+ handled well by our simple top-down parser"""
+ if not isinstance(x, tuple):
+ return x
+
+ op = x[0]
+ if op == 'parent':
+ # x^:y means (x^) : y, not x ^ (:y)
+ post = ('parentpost', x[1])
+ if x[2][0] == 'dagrangepre':
+ return _fixops(('dagrange', post, x[2][1]))
+ elif x[2][0] == 'rangepre':
+ return _fixops(('range', post, x[2][1]))
+
+ return (op,) + tuple(_fixops(y) for y in x[1:])
+
def _optimize(x, small):
if x is None:
return 0, x
@@ -2407,14 +2424,6 @@
elif op == 'group':
return _optimize(x[1], small)
elif op in 'dagrange range parent ancestorspec':
- if op == 'parent':
- # x^:y means (x^) : y, not x ^ (:y)
- post = ('parentpost', x[1])
- if x[2][0] == 'dagrangepre':
- return _optimize(('dagrange', post, x[2][1]), small)
- elif x[2][0] == 'rangepre':
- return _optimize(('range', post, x[2][1]), small)
-
wa, ta = _optimize(x[1], small)
wb, tb = _optimize(x[2], small)
return wa + wb, (op, ta, tb)
@@ -2470,7 +2479,7 @@
syminitletters=syminitletters))
if pos != len(spec):
raise error.ParseError(_('invalid token'), pos)
- return parser.simplifyinfixops(tree, ('list', 'or'))
+ return _fixops(parser.simplifyinfixops(tree, ('list', 'or')))
class _aliasrules(parser.basealiasrules):
"""Parsing and expansion rule set of revset aliases"""
--- a/tests/test-revset.t Sat Aug 06 19:59:28 2016 +0900
+++ b/tests/test-revset.t Sat Aug 06 20:21:00 2016 +0900
@@ -482,12 +482,7 @@
x^:y means (x^):y
- $ try --optimize '1^:2'
- (parent
- ('symbol', '1')
- (rangepre
- ('symbol', '2')))
- * optimized:
+ $ try '1^:2'
(range
(parentpost
('symbol', '1'))
@@ -498,12 +493,7 @@
1
2
- $ try --optimize '1^::2'
- (parent
- ('symbol', '1')
- (dagrangepre
- ('symbol', '2')))
- * optimized:
+ $ try '1^::2'
(dagrange
(parentpost
('symbol', '1'))
@@ -516,31 +506,18 @@
x^:y should be resolved before omitting group operators
- $ try --optimize '1^(:2)'
+ $ try '1^(:2)'
(parent
('symbol', '1')
(group
(rangepre
('symbol', '2'))))
- * optimized:
- (parent
- ('symbol', '1')
- (range
- ('string', '0')
- ('symbol', '2')))
hg: parse error: ^ expects a number 0, 1, or 2
[255]
x^:y should be resolved recursively
- $ try --optimize 'sort(1^:2)'
- (func
- ('symbol', 'sort')
- (parent
- ('symbol', '1')
- (rangepre
- ('symbol', '2'))))
- * optimized:
+ $ try 'sort(1^:2)'
(func
('symbol', 'sort')
(range
@@ -553,22 +530,14 @@
1
2
- $ try --optimize '(3^:4)^:2'
- (parent
- (group
- (parent
- ('symbol', '3')
- (rangepre
- ('symbol', '4'))))
- (rangepre
- ('symbol', '2')))
- * optimized:
+ $ try '(3^:4)^:2'
(range
(parentpost
- (range
- (parentpost
- ('symbol', '3'))
- ('symbol', '4')))
+ (group
+ (range
+ (parentpost
+ ('symbol', '3'))
+ ('symbol', '4'))))
('symbol', '2'))
* set:
<spanset+ 0:2>
@@ -576,22 +545,14 @@
1
2
- $ try --optimize '(3^::4)^::2'
- (parent
- (group
- (parent
- ('symbol', '3')
- (dagrangepre
- ('symbol', '4'))))
- (dagrangepre
- ('symbol', '2')))
- * optimized:
+ $ try '(3^::4)^::2'
(dagrange
(parentpost
- (dagrange
- (parentpost
- ('symbol', '3'))
- ('symbol', '4')))
+ (group
+ (dagrange
+ (parentpost
+ ('symbol', '3'))
+ ('symbol', '4'))))
('symbol', '2'))
* set:
<baseset+ [0, 1, 2]>
@@ -601,14 +562,9 @@
x^ in alias should also be resolved
- $ try --optimize 'A' --config 'revsetalias.A=1^:2'
+ $ try 'A' --config 'revsetalias.A=1^:2'
('symbol', 'A')
* expanded:
- (parent
- ('symbol', '1')
- (rangepre
- ('symbol', '2')))
- * optimized:
(range
(parentpost
('symbol', '1'))
@@ -619,7 +575,7 @@
1
2
- $ try --optimize 'A:2' --config 'revsetalias.A=1^'
+ $ try 'A:2' --config 'revsetalias.A=1^'
(range
('symbol', 'A')
('symbol', '2'))
@@ -628,11 +584,6 @@
(parentpost
('symbol', '1'))
('symbol', '2'))
- * optimized:
- (range
- (parentpost
- ('symbol', '1'))
- ('symbol', '2'))
* set:
<spanset+ 0:2>
0
@@ -642,7 +593,7 @@
but not beyond the boundary of alias expansion, because the resolution should
be made at the parsing stage
- $ try --optimize '1^A' --config 'revsetalias.A=:2'
+ $ try '1^A' --config 'revsetalias.A=:2'
(parent
('symbol', '1')
('symbol', 'A'))
@@ -651,17 +602,8 @@
('symbol', '1')
(rangepre
('symbol', '2')))
- * optimized:
- (range
- (parentpost
- ('symbol', '1'))
- ('symbol', '2'))
- * set:
- <spanset+ 0:2>
- 0
- 1
- 2
-BROKEN: should be parsed as '1^(:2)'
+ hg: parse error: ^ expects a number 0, 1, or 2
+ [255]
ancestor can accept 0 or more arguments