--- a/mercurial/revset.py Sat Jul 08 12:49:46 2017 +0900
+++ b/mercurial/revset.py Sat Jul 08 13:07:59 2017 +0900
@@ -151,6 +151,15 @@
def notset(repo, subset, x, order):
return subset - getset(repo, subset, x)
+def relationset(repo, subset, x, y, order):
+ raise error.ParseError(_("can't use a relation in this context"))
+
+def relsubscriptset(repo, subset, x, y, z, order):
+ raise error.ParseError(_("can't use a relation in this context"))
+
+def subscriptset(repo, subset, x, y, order):
+ raise error.ParseError(_("can't use a subscript in this context"))
+
def listset(repo, subset, *xs):
raise error.ParseError(_("can't use a list in this context"),
hint=_('see hg help "revsets.x or y"'))
@@ -2004,6 +2013,9 @@
"or": orset,
"not": notset,
"difference": differenceset,
+ "relation": relationset,
+ "relsubscript": relsubscriptset,
+ "subscript": subscriptset,
"list": listset,
"keyvalue": keyvaluepair,
"func": func,
--- a/mercurial/revsetlang.py Sat Jul 08 12:49:46 2017 +0900
+++ b/mercurial/revsetlang.py Sat Jul 08 13:07:59 2017 +0900
@@ -21,6 +21,8 @@
elements = {
# token-type: binding-strength, primary, prefix, infix, suffix
"(": (21, None, ("group", 1, ")"), ("func", 1, ")"), None),
+ "[": (21, None, None, ("subscript", 1, "]"), None),
+ "#": (21, None, None, ("relation", 21), None),
"##": (20, None, None, ("_concat", 20), None),
"~": (18, None, None, ("ancestor", 18), None),
"^": (18, None, None, ("parent", 18), "parentpost"),
@@ -39,6 +41,7 @@
"=": (3, None, None, ("keyvalue", 3), None),
",": (2, None, None, ("list", 2), None),
")": (0, None, None, None, None),
+ "]": (0, None, None, None, None),
"symbol": (0, "symbol", None, None, None),
"string": (0, "string", None, None, None),
"end": (0, None, None, None, None),
@@ -47,7 +50,7 @@
keywords = {'and', 'or', 'not'}
_quoteletters = {'"', "'"}
-_simpleopletters = set(pycompat.iterbytestr("():=,-|&+!~^%"))
+_simpleopletters = set(pycompat.iterbytestr("()[]#:=,-|&+!~^%"))
# default set of valid characters for the initial letter of symbols
_syminitletters = set(pycompat.iterbytestr(
@@ -331,6 +334,9 @@
# make number of arguments deterministic:
# x + y + z -> (or x y z) -> (or (list x y z))
return (op, _fixops(('list',) + x[1:]))
+ elif op == 'subscript' and x[1][0] == 'relation':
+ # x#y[z] ternary
+ return _fixops(('relsubscript', x[1][1], x[1][2], x[2]))
return (op,) + tuple(_fixops(y) for y in x[1:])
@@ -369,10 +375,16 @@
return (op, _analyze(x[1], defineorder), order)
elif op == 'group':
return _analyze(x[1], order)
- elif op in ('dagrange', 'range', 'parent', 'ancestor'):
+ elif op in ('dagrange', 'range', 'parent', 'ancestor', 'relation',
+ 'subscript'):
ta = _analyze(x[1], defineorder)
tb = _analyze(x[2], defineorder)
return (op, ta, tb, order)
+ elif op == 'relsubscript':
+ ta = _analyze(x[1], defineorder)
+ tb = _analyze(x[2], defineorder)
+ tc = _analyze(x[3], defineorder)
+ return (op, ta, tb, tc, order)
elif op == 'list':
return (op,) + tuple(_analyze(y, order) for y in x[1:])
elif op == 'keyvalue':
@@ -481,10 +493,14 @@
wb, tb = _optimize(x[2], small)
order = x[3]
return wa + wb, (op, ta, tb, order)
- elif op in ('parent', 'ancestor'):
+ elif op in ('parent', 'ancestor', 'relation', 'subscript'):
w, t = _optimize(x[1], small)
order = x[3]
return w, (op, t, x[2], order)
+ elif op == 'relsubscript':
+ w, t = _optimize(x[1], small)
+ order = x[4]
+ return w, (op, t, x[2], x[3], order)
elif op == 'list':
ws, ts = zip(*(_optimize(y, small) for y in x[1:]))
return sum(ws), (op,) + ts
--- a/tests/test-revset.t Sat Jul 08 12:49:46 2017 +0900
+++ b/tests/test-revset.t Sat Jul 08 13:07:59 2017 +0900
@@ -500,6 +500,151 @@
hg: parse error: can't use a key-value pair in this context
[255]
+relation-subscript operator has the highest binding strength (as function call):
+
+ $ hg debugrevspec -p parsed 'tip:tip^#generations[-1]'
+ * parsed:
+ (range
+ ('symbol', 'tip')
+ (relsubscript
+ (parentpost
+ ('symbol', 'tip'))
+ ('symbol', 'generations')
+ (negate
+ ('symbol', '1'))))
+ hg: parse error: can't use a relation in this context
+ [255]
+
+ $ hg debugrevspec -p parsed --no-show-revs 'not public()#generations[0]'
+ * parsed:
+ (not
+ (relsubscript
+ (func
+ ('symbol', 'public')
+ None)
+ ('symbol', 'generations')
+ ('symbol', '0')))
+ hg: parse error: can't use a relation in this context
+ [255]
+
+left-hand side of relation-subscript operator should be optimized recursively:
+
+ $ hg debugrevspec -p analyzed -p optimized --no-show-revs \
+ > '(not public())#generations[0]'
+ * analyzed:
+ (relsubscript
+ (not
+ (func
+ ('symbol', 'public')
+ None
+ any)
+ define)
+ ('symbol', 'generations')
+ ('symbol', '0')
+ define)
+ * optimized:
+ (relsubscript
+ (func
+ ('symbol', '_notpublic')
+ None
+ any)
+ ('symbol', 'generations')
+ ('symbol', '0')
+ define)
+ hg: parse error: can't use a relation in this context
+ [255]
+
+resolution of subscript and relation-subscript ternary operators:
+
+ $ hg debugrevspec -p analyzed 'tip[0]'
+ * analyzed:
+ (subscript
+ ('symbol', 'tip')
+ ('symbol', '0')
+ define)
+ hg: parse error: can't use a subscript in this context
+ [255]
+
+ $ hg debugrevspec -p analyzed 'tip#rel[0]'
+ * analyzed:
+ (relsubscript
+ ('symbol', 'tip')
+ ('symbol', 'rel')
+ ('symbol', '0')
+ define)
+ hg: parse error: can't use a relation in this context
+ [255]
+
+ $ hg debugrevspec -p analyzed '(tip#rel)[0]'
+ * analyzed:
+ (subscript
+ (relation
+ ('symbol', 'tip')
+ ('symbol', 'rel')
+ define)
+ ('symbol', '0')
+ define)
+ hg: parse error: can't use a subscript in this context
+ [255]
+
+ $ hg debugrevspec -p analyzed 'tip#rel[0][1]'
+ * analyzed:
+ (subscript
+ (relsubscript
+ ('symbol', 'tip')
+ ('symbol', 'rel')
+ ('symbol', '0')
+ define)
+ ('symbol', '1')
+ define)
+ hg: parse error: can't use a subscript in this context
+ [255]
+
+ $ hg debugrevspec -p analyzed 'tip#rel0#rel1[1]'
+ * analyzed:
+ (relsubscript
+ (relation
+ ('symbol', 'tip')
+ ('symbol', 'rel0')
+ define)
+ ('symbol', 'rel1')
+ ('symbol', '1')
+ define)
+ hg: parse error: can't use a relation in this context
+ [255]
+
+ $ hg debugrevspec -p analyzed 'tip#rel0[0]#rel1[1]'
+ * analyzed:
+ (relsubscript
+ (relsubscript
+ ('symbol', 'tip')
+ ('symbol', 'rel0')
+ ('symbol', '0')
+ define)
+ ('symbol', 'rel1')
+ ('symbol', '1')
+ define)
+ hg: parse error: can't use a relation in this context
+ [255]
+
+parse errors of relation, subscript and relation-subscript operators:
+
+ $ hg debugrevspec '[0]'
+ hg: parse error at 0: not a prefix: [
+ [255]
+ $ hg debugrevspec '.#'
+ hg: parse error at 2: not a prefix: end
+ [255]
+ $ hg debugrevspec '#rel'
+ hg: parse error at 0: not a prefix: #
+ [255]
+ $ hg debugrevspec '.#rel[0'
+ hg: parse error at 7: unexpected token: end
+ [255]
+ $ hg debugrevspec '.]'
+ hg: parse error at 1: invalid token
+ [255]
+
parsed tree at stages:
$ hg debugrevspec -p all '()'