[PATCH] revset: parse x^:: as (x^):: (issue5764)

Yuya Nishihara yuya at tcha.org
Sun Dec 31 12:23:02 UTC 2017


# HG changeset patch
# User Yuya Nishihara <yuya at tcha.org>
# Date 1514624123 -32400
#      Sat Dec 30 17:55:23 2017 +0900
# Node ID 4d5be53b4adbc913cfbded05c94307ec3ced1f06
# Parent  e01549a7bf0a6a7adbbb317a5d4bfde36c205b4d
revset: parse x^:: as (x^):: (issue5764)

We have to make '::' a valid primary expression to parse 'x^::' as '(x)^(::)'
first, but that doesn't change the language because a prefix operator '::y'
precedes a primary '::'.

I can't think of an intuitive meaning of '::', so it's just rejected. Given
'x::y' can be considered to default to {x = roots(), y = heads()}, '::' could
be 'roots()::heads()', which seems not any useful.

diff --git a/mercurial/revsetlang.py b/mercurial/revsetlang.py
--- a/mercurial/revsetlang.py
+++ b/mercurial/revsetlang.py
@@ -27,8 +27,10 @@ elements = {
     "~": (18, None, None, ("ancestor", 18), None),
     "^": (18, None, None, ("parent", 18), "parentpost"),
     "-": (5, None, ("negate", 19), ("minus", 5), None),
-    "::": (17, None, ("dagrangepre", 17), ("dagrange", 17), "dagrangepost"),
-    "..": (17, None, ("dagrangepre", 17), ("dagrange", 17), "dagrangepost"),
+    "::": (17, "dagrangeall", ("dagrangepre", 17), ("dagrange", 17),
+           "dagrangepost"),
+    "..": (17, "dagrangeall", ("dagrangepre", 17), ("dagrange", 17),
+           "dagrangepost"),
     ":": (15, "rangeall", ("rangepre", 15), ("range", 15), "rangepost"),
     "not": (10, None, ("not", 10), None, None),
     "!": (10, None, ("not", 10), None, None),
@@ -288,6 +290,8 @@ def _fixops(x):
         post = ('parentpost', x[1])
         if x[2][0] == 'dagrangepre':
             return _fixops(('dagrange', post, x[2][1]))
+        elif x[2][0] == 'dagrangeall':
+            return _fixops(('dagrangepost', post))
         elif x[2][0] == 'rangepre':
             return _fixops(('range', post, x[2][1]))
         elif x[2][0] == 'rangeall':
@@ -313,6 +317,8 @@ def _analyze(x):
         return _analyze(_build('only(_, _)', *x[1:]))
     elif op == 'onlypost':
         return _analyze(_build('only(_)', x[1]))
+    elif op == 'dagrangeall':
+        raise error.ParseError(_("can't use '::' in this context"))
     elif op == 'dagrangepre':
         return _analyze(_build('ancestors(_)', x[1]))
     elif op == 'dagrangepost':
diff --git a/tests/test-revset.t b/tests/test-revset.t
--- a/tests/test-revset.t
+++ b/tests/test-revset.t
@@ -792,7 +792,7 @@ may be hidden (issue5385)
   * set:
   <baseset []>
 
-infix/suffix resolution of ^ operator (issue2884):
+infix/suffix resolution of ^ operator (issue2884, issue5764):
 
  x^:y means (x^):y
 
@@ -818,6 +818,17 @@ infix/suffix resolution of ^ operator (i
   1
   2
 
+  $ try '1^..2'
+  (dagrange
+    (parentpost
+      (symbol '1'))
+    (symbol '2'))
+  * set:
+  <baseset+ [0, 1, 2]>
+  0
+  1
+  2
+
   $ try '9^:'
   (rangepost
     (parentpost
@@ -827,6 +838,24 @@ infix/suffix resolution of ^ operator (i
   8
   9
 
+  $ try '9^::'
+  (dagrangepost
+    (parentpost
+      (symbol '9')))
+  * set:
+  <generatorsetasc+>
+  8
+  9
+
+  $ try '9^..'
+  (dagrangepost
+    (parentpost
+      (symbol '9')))
+  * set:
+  <generatorsetasc+>
+  8
+  9
+
  x^:y should be resolved before omitting group operators
 
   $ try '1^(:2)'
@@ -944,6 +973,14 @@ infix/suffix resolution of ^ operator (i
   hg: parse error: ^ expects a number 0, 1, or 2
   [255]
 
+'::' itself isn't a valid expression
+
+  $ try '::'
+  (dagrangeall
+    None)
+  hg: parse error: can't use '::' in this context
+  [255]
+
 ancestor can accept 0 or more arguments
 
   $ log 'ancestor()'


More information about the Mercurial-devel mailing list